diff --git a/FadeBasic/CHANGELOG.md b/FadeBasic/CHANGELOG.md
index dfdb502..fe878e9 100644
--- a/FadeBasic/CHANGELOG.md
+++ b/FadeBasic/CHANGELOG.md
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [0.0.37] - 2025-03-02
+
+### Changed
+- VM register max count increased from `byte` to `ulong`.
+- VM heap max size increased from ~ 2^31 to ~ 2^64.
+
## [0.0.36] - 2025-02-26
### Fixed
diff --git a/FadeBasic/CommandSourceGenerator/Generator.cs b/FadeBasic/CommandSourceGenerator/Generator.cs
index 24a1c56..b2e1105 100644
--- a/FadeBasic/CommandSourceGenerator/Generator.cs
+++ b/FadeBasic/CommandSourceGenerator/Generator.cs
@@ -413,7 +413,8 @@ static string GetReturnSource(CommandDescriptor descriptor)
sb.AppendLine($"{nameof(VmConverter)}.{nameof(VmConverter.FromStringSpan)}({result}, out var {resultSpan});");
sb.AppendLine($"{VM}.{nameof(VirtualMachine.heap)}.{nameof(VirtualMachine.heap.AllocateString)}({resultSpan}.Length, out var {resultStrPtr});");
sb.AppendLine($"{VM}.{nameof(VirtualMachine.heap)}.{nameof(VirtualMachine.heap.WriteSpan)}({resultStrPtr}, {resultSpan}.Length, {resultSpan});");
- sb.AppendLine($"var {ptrIntBytes} = {nameof(BitConverter)}.{nameof(BitConverter.GetBytes)}({resultStrPtr});");
+ // sb.AppendLine($"var {ptrIntBytes} = {nameof(BitConverter)}.{nameof(BitConverter.GetBytes)}({resultStrPtr});");
+ sb.AppendLine($"var {ptrIntBytes} = {nameof(VmPtr)}.{nameof(VmPtr.GetBytes)}(ref {resultStrPtr});");
sb.AppendLine($"{nameof(VmUtil)}.{nameof(VmUtil.PushSpan)}(ref {VM}.{nameof(VirtualMachine.stack)}, {ptrIntBytes}, {TypeCodes.STRING});");
diff --git a/FadeBasic/FadeBasic/FadeBasic.csproj b/FadeBasic/FadeBasic/FadeBasic.csproj
index 9ff81aa..9ba2fb6 100644
--- a/FadeBasic/FadeBasic/FadeBasic.csproj
+++ b/FadeBasic/FadeBasic/FadeBasic.csproj
@@ -11,7 +11,6 @@
FadeBasic.Lang.Core
FadeBasic Language Core
Fade's actually dotnet embeddable Basic.
-
diff --git a/FadeBasic/FadeBasic/FadeBasicCommandAttribute.cs b/FadeBasic/FadeBasic/FadeBasicCommandAttribute.cs
index 513afb4..fb8ec7f 100644
--- a/FadeBasic/FadeBasic/FadeBasicCommandAttribute.cs
+++ b/FadeBasic/FadeBasic/FadeBasicCommandAttribute.cs
@@ -23,7 +23,7 @@ public class FromVmAttribute : Attribute
public struct RawArg
{
public T value;
- public int address;
+ public ulong address;
public CommandArgRuntimeState state;
}
}
\ No newline at end of file
diff --git a/FadeBasic/FadeBasic/Json/IJsonable.cs b/FadeBasic/FadeBasic/Json/IJsonable.cs
index 1d99356..96f3cd7 100644
--- a/FadeBasic/FadeBasic/Json/IJsonable.cs
+++ b/FadeBasic/FadeBasic/Json/IJsonable.cs
@@ -16,6 +16,12 @@ public interface IJsonable
void ProcessJson(IJsonOperation op);
}
+ public interface IJsonableSerializationCallbacks : IJsonable
+ {
+ void OnAfterDeserialized();
+ void OnBeforeSerialize();
+ }
+
public interface IJsonOperation
{
void Process(IJsonable jsonable);
@@ -52,7 +58,7 @@ public static class JsonableExtensions
{
var instance = new T();
var op = new JsonReadOp(json);
- instance.ProcessJson(op);
+ op.Process(instance);
return instance;
}
@@ -376,7 +382,13 @@ public JsonReadOp(JsonData data)
public void Process(IJsonable jsonable)
{
+
jsonable.ProcessJson(this);
+
+ if (jsonable is IJsonableSerializationCallbacks cbr)
+ {
+ cbr.OnAfterDeserialized();
+ }
}
public void IncludeField(string name, ref int fieldValue)
@@ -390,6 +402,11 @@ public void IncludeField(string name, ref byte fieldValue)
fieldValue = (byte)byteValue;
}
+ public void IncludeField(string name, ref ulong fieldValue)
+ {
+ throw new NotImplementedException();
+ }
+
public void IncludeField(string name, ref bool fieldValue)
{
_data.ints.TryGetValue(name, out var byteValue);
@@ -538,12 +555,17 @@ void IncludePrim(string name, ref T prim) where T : struct
public void Process(IJsonable jsonable)
{
_sb.Append(JsonConstants.OPEN_BRACKET);
+ if (jsonable is IJsonableSerializationCallbacks cbr)
+ {
+ cbr.OnBeforeSerialize();
+ }
jsonable.ProcessJson(this);
_sb.Append(JsonConstants.CLOSE_BRACKET);
}
public void IncludeField(string name, ref int fieldValue) => IncludePrim(name, ref fieldValue);
public void IncludeField(string name, ref byte fieldValue) => IncludePrim(name, ref fieldValue);
+ public void IncludeField(string name, ref ulong fieldValue) => IncludePrim(name, ref fieldValue);
public void IncludeField(string name, ref bool fieldValue)
{
diff --git a/FadeBasic/FadeBasic/Launch/DebugSession.cs b/FadeBasic/FadeBasic/Launch/DebugSession.cs
index 9b4b06d..1bccf5c 100644
--- a/FadeBasic/FadeBasic/Launch/DebugSession.cs
+++ b/FadeBasic/FadeBasic/Launch/DebugSession.cs
@@ -683,7 +683,7 @@ void AddVariable(DebugVariable local, bool isGlobal)
{
typeCode = variable.typeCode,
name = local.name,
- registerAddress = (byte)variable.regAddr,
+ registerAddress = variable.regAddr,
byteSize = TypeCodes.GetByteSize(variable.typeCode),
structType = structName,
isGlobal = isGlobal
@@ -730,7 +730,7 @@ void AddVariable(DebugVariable local, bool isGlobal)
var rankExprs = new IExpressionNode[arrayRankCount];
for (var i = 0; i < arrayRankCount; i++)
{
- var rankStrideRegAddr = variable.regAddr + arrayRankCount * 2 - (i * 2) ;
+ var rankStrideRegAddr = variable.regAddr + (ulong)arrayRankCount * 2 - ((ulong)i * 2) ;
var rankSizeRegAddr = rankStrideRegAddr - 1;
var rankSize = _vm.scopeStack.buffer[variable.scopeIndex]
.dataRegisters[rankSizeRegAddr];
@@ -1010,7 +1010,7 @@ void AddVariable(DebugVariable local, bool isGlobal)
if (synth.typeCode == TypeCodes.STRUCT)
{
var ptr = _vm.dataRegisters[synth.registerAddress];
- if (!_vm.heap.TryGetAllocation((int)ptr, out var alloc))
+ if (!_vm.heap.TryGetAllocation(VmPtr.FromRaw(ptr), out var alloc))
{
return DebugEvalResult.Failed(
$"invalid heap, reg=[{synth.registerAddress}] data=[{ptr}] which is not a valid heap pointer");
diff --git a/FadeBasic/FadeBasic/Sdk/Fade.cs b/FadeBasic/FadeBasic/Sdk/Fade.cs
index f4138b3..ca66563 100644
--- a/FadeBasic/FadeBasic/Sdk/Fade.cs
+++ b/FadeBasic/FadeBasic/Sdk/Fade.cs
@@ -437,11 +437,11 @@ public bool TryGetString(string name, out string value, out string error)
return false;
}
- var address = VmUtil.ConvertToInt(scope.dataRegisters[index]);
+ var address = VmUtil.ConvertToPtr(scope.dataRegisters[index]);
return TryReadString(address, out value, out error);
}
- bool TryReadString(int address, out string value, out string error)
+ bool TryReadString(VmPtr address, out string value, out string error)
{
value = null;
error = null;
@@ -514,7 +514,7 @@ private bool TryGetArray(string name, ref FadeArray value, out string erro
}
- var address = VmUtil.ConvertToInt(scope.dataRegisters[index]);
+ var address = VmUtil.ConvertToPtr(scope.dataRegisters[index]);
if (!Machine.heap.TryGetAllocation(address, out var allocation))
{
error = "invalid memory address";
@@ -592,14 +592,14 @@ public bool TryGetObject(string name, out FadeObject value, out string error)
return false;
}
- var address = VmUtil.ConvertToInt(scope.dataRegisters[index]);
+ var address = VmUtil.ConvertToPtr(scope.dataRegisters[index]);
return TryReadObject(address, out value, out error);
}
- bool TryReadObject(int address, out FadeObject value, out string error)
+ bool TryReadObject(VmPtr address, out FadeObject value, out string error)
{
value = null;
error = null;
@@ -663,7 +663,8 @@ void ReadMember(ref VmAllocation allocation, int offset, FadeObject value, strin
value.doubleFloatFields[fieldName] = BitConverter.ToDouble(memory, member.Offset + offset);
break;
case TypeCodes.STRING:
- var strPtr = BitConverter.ToInt32(memory, member.Offset + offset);
+ var strPtr = allocation.ptr + member.Offset + offset;
+ // var strPtr = BitConverter.ToInt32(memory, member.Offset + offset);
TryReadString(strPtr, out var strValue, out _);
value.stringFields[fieldName] = strValue;
break;
diff --git a/FadeBasic/FadeBasic/Virtual/Compiler.cs b/FadeBasic/FadeBasic/Virtual/Compiler.cs
index ec028a5..218e4d3 100644
--- a/FadeBasic/FadeBasic/Virtual/Compiler.cs
+++ b/FadeBasic/FadeBasic/Virtual/Compiler.cs
@@ -8,13 +8,15 @@
namespace FadeBasic.Virtual
{
- public class CompiledVariable : IJsonable
+ public class CompiledVariable : IJsonable, IJsonableSerializationCallbacks
{
public byte byteSize;
public byte typeCode;
public string name;
public string structType;
- public byte registerAddress;
+ public ulong registerAddress;
+
+ private string registerAddressSerializer;
public bool isGlobal;
public void ProcessJson(IJsonOperation op)
@@ -23,18 +25,31 @@ public void ProcessJson(IJsonOperation op)
op.IncludeField(nameof(typeCode), ref typeCode);
op.IncludeField(nameof(name), ref name);
op.IncludeField(nameof(structType), ref structType);
- op.IncludeField(nameof(registerAddress), ref registerAddress);
+ op.IncludeField(nameof(registerAddressSerializer), ref registerAddressSerializer);
op.IncludeField(nameof(isGlobal), ref isGlobal);
}
+
+ public void OnAfterDeserialized()
+ {
+ registerAddress = ulong.Parse(registerAddressSerializer);
+ }
+
+ public void OnBeforeSerialize()
+ {
+ registerAddressSerializer = registerAddress.ToString();
+ }
}
- public class CompiledArrayVariable : IJsonable
+ public class CompiledArrayVariable : IJsonable, IJsonableSerializationCallbacks
{
public int byteSize;
public byte typeCode;
public string name;
public CompiledType structType;
- public byte registerAddress;
+ public ulong registerAddress;
+
+ private string registerAddressSerializer;
+
public bool isGlobal;
public byte[] rankSizeRegisterAddresses; // an array where the index is the rank, and the value is the ptr to a register whose value holds the size of the rank
public byte[] rankIndexScalerRegisterAddresses; // an array where the index is the rank, and the value is the ptr to a register whose value holds the multiplier factor for the rank's indexing
@@ -44,11 +59,21 @@ public void ProcessJson(IJsonOperation op)
op.IncludeField(nameof(typeCode), ref typeCode);
op.IncludeField(nameof(name), ref name);
op.IncludeField(nameof(structType), ref structType);
- op.IncludeField(nameof(registerAddress), ref registerAddress);
+ op.IncludeField(nameof(registerAddressSerializer), ref registerAddressSerializer);
op.IncludeField(nameof(isGlobal), ref isGlobal);
op.IncludeField(nameof(rankSizeRegisterAddresses), ref rankSizeRegisterAddresses);
op.IncludeField(nameof(rankIndexScalerRegisterAddresses), ref rankIndexScalerRegisterAddresses);
}
+
+ public void OnAfterDeserialized()
+ {
+ registerAddress = ulong.Parse(registerAddressSerializer);
+ }
+
+ public void OnBeforeSerialize()
+ {
+ registerAddressSerializer = registerAddress.ToString();
+ }
}
public class CompiledType : IJsonable
@@ -95,7 +120,7 @@ public struct FunctionCallReplacement
public class CompileScope
{
- public int registerCount;
+ public ulong registerCount;
private Dictionary _varToReg = new Dictionary();
@@ -111,7 +136,7 @@ public CompileScope(Dictionary varToReg, Dictionary highestAddress)
@@ -153,7 +178,7 @@ public CompiledVariable Create(string name, byte typeCode, bool isGlobal, byte r
{
var compileVar = new CompiledVariable
{
- registerAddress = (byte)(regOffset + registerCount++),
+ registerAddress = (regOffset + registerCount++),
name = name,
typeCode = typeCode,
byteSize = TypeCodes.GetByteSize(typeCode),
@@ -199,17 +224,53 @@ public class CompilerOptions
};
}
+ public class InternedScopeMetadata : IJsonableSerializationCallbacks
+ {
+ public int scopeIndex;
+ public ulong maxRegisterSize;
+ private string maxRegisterSizeSerializer;
+
+ public void ProcessJson(IJsonOperation op)
+ {
+ op.IncludeField(nameof(scopeIndex), ref scopeIndex);
+ op.IncludeField(nameof(maxRegisterSizeSerializer), ref maxRegisterSizeSerializer);
+ }
+
+ public void OnAfterDeserialized()
+ {
+ maxRegisterSize = ulong.Parse(maxRegisterSizeSerializer);
+ }
+
+ public void OnBeforeSerialize()
+ {
+ maxRegisterSizeSerializer = maxRegisterSize.ToString();
+ }
+ }
- public class InternedData : IJsonable
+ public class InternedData : IJsonable, IJsonableSerializationCallbacks
{
public Dictionary types;
public Dictionary functions = new Dictionary();
public List strings = new List();
+ // public Dictionary scopeMetaDatas = new Dictionary();
+ public ulong maxRegisterAddress;
+ private string maxRegisterAddressSerializer;
public void ProcessJson(IJsonOperation op)
{
op.IncludeField(nameof(types), ref types);
op.IncludeField(nameof(functions), ref functions);
op.IncludeField(nameof(strings), ref strings);
+ op.IncludeField(nameof(maxRegisterAddressSerializer), ref maxRegisterAddressSerializer);
+ }
+
+ public void OnAfterDeserialized()
+ {
+ maxRegisterAddress = ulong.Parse(maxRegisterAddressSerializer);
+ }
+
+ public void OnBeforeSerialize()
+ {
+ maxRegisterAddressSerializer = maxRegisterAddress.ToString();
}
}
@@ -490,6 +551,8 @@ public void PushInternedData()
data.types.Add(type.name, type);
}
+ data.maxRegisterAddress = scopeStack.Peek().registerCount;
+ data.maxRegisterAddress += 1; // an extra 1 for debugging room.
var json = data.Jsonify();
var jsonBytes = Encoding.Default.GetBytes(json);
_buffer.AddRange(jsonBytes);
@@ -765,9 +828,7 @@ private void Compile(FunctionStatement functionStatement)
}
-
-
- _buffer.Add(OpCodes.BREAKPOINT);
+
// compile all the statements...
foreach (var statement in functionStatement.statements)
{
@@ -1373,10 +1434,9 @@ private void Compile(AddressExpression expression)
default:
// anything else is a registry ptr!
var regAddr = variable.registerAddress;
- AddPush(_buffer, new byte[]
- {
- regAddr
- }, variable.isGlobal ? TypeCodes.PTR_GLOBAL_REG : TypeCodes.PTR_REG);
+ _buffer.Add(OpCodes.PUSH);
+ _buffer.Add(variable.isGlobal ? TypeCodes.PTR_GLOBAL_REG : TypeCodes.PTR_REG);
+ AddPushULongNoTypeCode(_buffer, regAddr);
break;
}
@@ -1701,7 +1761,6 @@ public void Compile(DeclarationStatement declaration, bool includeDefaultInitial
// _buffer.Add(OpCodes.STORE);
// _buffer.Add(arrayVar.rankIndexScalerRegisterAddresses[i]); // store the multiplier
PushStore(_buffer, arrayVar.rankIndexScalerRegisterAddresses[i], arrayVar.isGlobal);
-
}
@@ -1832,29 +1891,36 @@ public void PushAddress(ArrayIndexReference arrayRefNode)
_buffer.Add(OpCodes.MUL);
// load the array's ptr onto the stack, this is for the math of the offset
- PushLoad(_buffer, compiledArrayVar.registerAddress, compiledArrayVar.isGlobal);
-
-
+ PushLoadPtr(_buffer, compiledArrayVar.registerAddress, compiledArrayVar.isGlobal);
+
// add the offset to the original pointer to get the write location
_buffer.Add(OpCodes.ADD);
}
- static void PushStorePtr(List buffer, byte regAddr, bool isGlobal)
+ static void PushStorePtr(List buffer, ulong regAddr, bool isGlobal)
{
buffer.Add(isGlobal ? OpCodes.STORE_PTR_GLOBAL : OpCodes.STORE_PTR);
- buffer.Add(regAddr);
+ // buffer.Add(regAddr);
+ AddPushULongNoTypeCode(buffer, regAddr);
+ }
+ static void PushLoadPtr(List buffer, ulong regAddr, bool isGlobal)
+ {
+ buffer.Add(isGlobal ? OpCodes.LOAD_PTR_GLOBAL : OpCodes.LOAD_PTR);
+ // buffer.Add(regAddr);
+ AddPushULongNoTypeCode(buffer, regAddr);
}
- static void PushStore(List buffer, byte registerAddress, bool isGlobal)
+ static void PushStore(List buffer, ulong registerAddress, bool isGlobal)
{
buffer.Add(isGlobal ? OpCodes.STORE_GLOBAL : OpCodes.STORE);
- buffer.Add(registerAddress);
+ AddPushULongNoTypeCode(buffer, registerAddress);
+
}
- static void PushLoad(List buffer, byte registerAddress, bool isGlobal)
+ static void PushLoad(List buffer, ulong registerAddress, bool isGlobal)
{
buffer.Add(isGlobal ? OpCodes.LOAD_GLOBAL : OpCodes.LOAD);
- buffer.Add(registerAddress);
+ AddPushULongNoTypeCode(buffer, registerAddress);
}
void CompileStructData(CompiledVariable compiledVar, bool ignoreType=true)
@@ -1872,9 +1938,6 @@ void CompileStructData(CompiledVariable compiledVar, bool ignoreType=true)
// now, push the pointer where to write the data to- which, we know is the register address
PushLoad(_buffer, compiledVar.registerAddress, compiledVar.isGlobal);
-
- // the address is a struct ref, not an int, so for the write-command to work, we need to cast the struct to an int
- CastToInt();
_buffer.Add(OpCodes.WRITE); // consume the ptr, then the length, then the data
}
@@ -2043,7 +2106,8 @@ void CompileAssignmentLeftHandSide(IVariableNode variable)
PushLoad(_buffer, compiledVar.registerAddress, compiledVar.isGlobal);
// load the offset of the right side
- AddPushInt(_buffer, offset);
+ // AddPushInt(_buffer, offset);
+ AddPushPtr(_buffer, new VmPtr(){memoryPtr = offset}, TypeCodes.PTR_HEAP);
// sum them, then the result is the ptr on the stack
_buffer.Add(OpCodes.ADD);
@@ -2082,8 +2146,13 @@ public void Compile(AssignmentStatement assignmentStatement)
Compile(assignmentStatement.expression);
CompileAssignmentLeftHandSide(assignmentStatement.variable);
+ if (test++ > 330)
+ {
+
+ }
}
+ private int test = 0;
public void ComputeStructOffsets(CompiledType baseType, IVariableNode right, out int offset, out int writeLength, out byte typeCode)
{
writeLength = 0;
@@ -2182,7 +2251,8 @@ public void Compile(IExpressionNode expr)
// push a fake pointer onto the stack... The value gets replaced
// at RUNTIME as the machine is allocating the interned strings.
// AddPushUInt(_buffer, int.MaxValue, includeTypeCode: false);
- AddPushInt(_buffer, int.MaxValue);
+ // AddPushInt(_buffer, int.MaxValue);
+ AddPushPtr(_buffer, VmPtr.TEMP, TypeCodes.PTR_HEAP);
}
else
{
@@ -2279,12 +2349,15 @@ public void Compile(IExpressionNode expr)
AddPushInt(_buffer, readLength);
// push the read offset, so that we can add it to the ptr
- AddPushInt(_buffer, readOffset);
+ // AddPushInt(_buffer, readOffset);
+ AddPushPtr(_buffer, new VmPtr{memoryPtr = readOffset}, TypeCodes.PTR_HEAP);
// push the ptr of the variable, and cast it to an int for easy math
PushLoad(_buffer, typeCompiledVar.registerAddress, typeCompiledVar.isGlobal);
- _buffer.Add(OpCodes.CAST);
- _buffer.Add(TypeCodes.INT);
+
+ // TODO: I removed these as part of the PTR refactor?
+ // _buffer.Add(OpCodes.CAST);
+ // _buffer.Add(TypeCodes.INT);
// add those two op codes back together...
_buffer.Add(OpCodes.ADD);
@@ -2348,9 +2421,7 @@ public void Compile(IExpressionNode expr)
// load the size up
AddPushInt(_buffer, structType.byteSize);
- // PushAddress(arrayRef);
PushLoad(_buffer, compiledVar.registerAddress, compiledVar.isGlobal);
- CastToInt();
// read, it'll find the ptr, size, and then place the data onto the stack
_buffer.Add(OpCodes.READ);
@@ -2584,6 +2655,18 @@ private static void AddPushTypeFormat(List buffer, ref HeapTypeFormat form
buffer.Add(OpCodes.PUSH_TYPE_FORMAT);
HeapTypeFormat.AddToBuffer(ref format, buffer);
}
+
+ private static void AddPushPtr(List buffer, VmPtr ptr, byte typeCode)
+ {
+ buffer.Add(OpCodes.PUSH);
+ buffer.Add(typeCode);
+ var value = VmPtr.GetBytes(ref ptr);
+ for (var i = 0; i < value.Length; i++)
+ // for (var i = value.Length - 1; i >= 0; i--)
+ {
+ buffer.Add(value[i]);
+ }
+ }
private static void AddPushInt(List buffer, int x)
{
@@ -2596,9 +2679,18 @@ private static void AddPushInt(List buffer, int x)
buffer.Add(value[i]);
}
}
+
+ private static void AddPushULongNoTypeCode(List buffer, ulong x)
+ {
+ var value = BitConverter.GetBytes(x);
+ for (var i = 0 ; i < value.Length; i ++)
+ {
+ buffer.Add(value[i]);
+ }
+ }
+
private static void AddPushUInt(List buffer, uint x, bool includeTypeCode=true)
{
-
if (includeTypeCode)
{
buffer.Add(OpCodes.PUSH);
diff --git a/FadeBasic/FadeBasic/Virtual/DebugUtil.cs b/FadeBasic/FadeBasic/Virtual/DebugUtil.cs
index fb4915d..8bc074f 100644
--- a/FadeBasic/FadeBasic/Virtual/DebugUtil.cs
+++ b/FadeBasic/FadeBasic/Virtual/DebugUtil.cs
@@ -10,12 +10,12 @@ public class DebugRuntimeVariable
public readonly byte typeCode;
public ulong rawValue; // could be a ptr.
public readonly int scopeIndex;
- public readonly int regAddr;
+ public readonly ulong regAddr;
public readonly VmAllocation allocation;
public readonly VirtualMachine vm;
- public DebugRuntimeVariable(VirtualMachine vm, string name, byte typeCode, ulong rawValue, ref VmAllocation allocation, int scopeIndex, int regAddr)
+ public DebugRuntimeVariable(VirtualMachine vm, string name, byte typeCode, ulong rawValue, ref VmAllocation allocation, int scopeIndex, ulong regAddr)
{
this.vm = vm;
this.name = name;
@@ -26,7 +26,7 @@ public DebugRuntimeVariable(VirtualMachine vm, string name, byte typeCode, ulong
this.regAddr = regAddr;
}
- public DebugRuntimeVariable(VirtualMachine vm, string name, byte typeCode, ulong rawValue, int scopeIndex, int regAddr)
+ public DebugRuntimeVariable(VirtualMachine vm, string name, byte typeCode, ulong rawValue, int scopeIndex, ulong regAddr)
{
this.vm = vm;
@@ -39,7 +39,7 @@ public DebugRuntimeVariable(VirtualMachine vm, string name, byte typeCode, ulong
// we know at this moment if the rawValue is a ptr or not...
if (typeCode == TypeCodes.STRUCT || typeCode == TypeCodes.STRING)
{
- if (!this.vm.heap.TryGetAllocation((int) rawValue, out allocation))
+ if (!this.vm.heap.TryGetAllocation(VmPtr.FromRaw(rawValue), out allocation))
{
throw new InvalidOperationException("There is no allocation for the struct reference. hh");
}
@@ -66,7 +66,7 @@ public string GetValueDisplay()
case TypeCodes.BYTE:
return VmUtil.ConvertToByte(rawValue).ToString();
case TypeCodes.STRING:
- var address = (int)rawValue;
+ var address = VmPtr.FromRaw(rawValue);
if (vm.heap.TryGetAllocationSize(address, out var strSize))
{
vm.heap.Read(address, strSize, out var strBytes);
@@ -142,7 +142,7 @@ public int GetElementCount(out byte rankCount, out bool isArray)
* Then move backwards by our current rank index (-arrayRankIndex*2)
* And then of the two registers, the element size is 1 back.
*/
- var elementRegAddr = regAddr + rankCount * 2 - (arrayRankIndex * 2 ) - 1;
+ ulong elementRegAddr = regAddr + (ulong)rankCount * 2 - ((ulong)arrayRankIndex * 2 ) - 1;
var elementCount = scope.dataRegisters[elementRegAddr];
return (int)elementCount;
@@ -344,7 +344,7 @@ public DebugScope Expand(int variableRequestVariableId)
var elementTypeCode = variable.allocation.format.typeCode;
// TODO: replace this with the stide in the dataRegisters...
- var elementRegAddr = variable.regAddr + arrayRanks * 2 - (variable.arrayRankIndex * 2 );
+ var elementRegAddr = variable.regAddr + (ulong)arrayRanks * 2 - ((ulong)variable.arrayRankIndex * 2 );
var strideLength = (int)_vm.scopeStack.buffer[variable.scopeIndex].dataRegisters[elementRegAddr];
_logger.Log($"found stride length=[{strideLength}] at reg=[{elementRegAddr}]");
var elementSize = (int)TypeCodes.GetByteSize(elementTypeCode);
@@ -384,7 +384,7 @@ public DebugScope Expand(int variableRequestVariableId)
var ptr = variable.rawValue + (ulong)(elementSize * i * strideLength);
var alloc = new VmAllocation
{
- ptr = (int)ptr,
+ ptr = VmPtr.FromRaw(ptr),
length = elementSize,
format = new HeapTypeFormat
{
@@ -444,7 +444,7 @@ public DebugScope Expand(int variableRequestVariableId)
}
else
{
- _vm.heap.ReadSpan((int)variable.rawValue + elementSize * i, elementSize,
+ _vm.heap.ReadSpan(VmPtr.FromRaw(variable.rawValue) + elementSize * i, elementSize,
out var fieldSpan);
subVariable.value =
VmUtil.ConvertValueToDisplayString(elementTypeCode, _vm, ref fieldSpan);
@@ -479,7 +479,7 @@ public DebugScope Expand(int variableRequestVariableId)
var ptr = variable.rawValue + (ulong)field.offset;
var alloc = new VmAllocation
{
- ptr = (int)ptr,
+ ptr = VmPtr.FromRaw(ptr),
length = field.length,
format = new HeapTypeFormat
{
@@ -523,7 +523,7 @@ public DebugScope Expand(int variableRequestVariableId)
};
evalNameToId[subVariable.evalName] = subVariable.id;
- _vm.heap.ReadSpan((int)variable.rawValue + field.offset, field.length, out var fieldSpan);
+ _vm.heap.ReadSpan(VmPtr.FromRaw(variable.rawValue) + field.offset, field.length, out var fieldSpan);
VmUtil.TryGetVariableTypeDisplay(field.typeCode, out subVariable.type);
subVariable.value =
VmUtil.ConvertValueToDisplayString(field.typeCode, _vm, ref fieldSpan);
@@ -673,7 +673,7 @@ public static class DebugUtil
public static Dictionary LookupVariablesFromScope(VirtualMachine vm, Dictionary results, DebugData dbg, int vmScopeIndex, bool global)
{
var scope = vm.scopeStack.buffer[vmScopeIndex];
- for (var scopeIndex = 0; scopeIndex < scope.dataRegisters.Length; scopeIndex++)
+ for (ulong scopeIndex = 0; scopeIndex < (ulong)scope.dataRegisters.LongLength; scopeIndex++)
{
var insIndex = scope.insIndexes[scopeIndex];
if (!dbg.insToVariable.TryGetValue(insIndex, out var variable))
@@ -689,7 +689,7 @@ public static Dictionary LookupVariablesFromScope(
if (variable.isPtr > 0)
{
- if (!vm.heap.TryGetAllocation((int)scope.dataRegisters[scopeIndex], out var allocation))
+ if (!vm.heap.TryGetAllocation(VmPtr.FromRaw(scope.dataRegisters[scopeIndex]), out var allocation))
{
throw new InvalidOperationException($"Could not get allocation for pointer based variable=[{variable.name}]");
}
diff --git a/FadeBasic/FadeBasic/Virtual/OpCodes.cs b/FadeBasic/FadeBasic/Virtual/OpCodes.cs
index db16256..0263459 100644
--- a/FadeBasic/FadeBasic/Virtual/OpCodes.cs
+++ b/FadeBasic/FadeBasic/Virtual/OpCodes.cs
@@ -29,11 +29,11 @@ public static class TypeCodes
public const byte DINT = 0x06; // 8 bytes (long)
public const byte DFLOAT = 0x07; // 8 bytes (double)
public const byte VOID = 0x08; // 0 bytes
- public const byte STRING = 0x09; // 4 bytes (ptr)
- public const byte PTR_REG = 0x0A; // 1 byte (registry ptr)
- public const byte PTR_HEAP = 0x0B; // 4 bytes (heap ptr)
- public const byte STRUCT = 0x0C; // 4 bytes (ptr)
- public const byte PTR_GLOBAL_REG = 0x0D; // 1 byte (global registry ptr)
+ public const byte STRING = 0x09; // 8 bytes (ptr)
+ public const byte PTR_REG = 0x0A; // 8 byte (registry ptr)
+ public const byte PTR_HEAP = 0x0B; // 8 bytes (heap ptr)
+ public const byte STRUCT = 0x0C; // 8 bytes (ptr), bucket and ptr
+ public const byte PTR_GLOBAL_REG = 0x0D; // 8 byte (global registry ptr)
public const byte ANY = 254; // this isn't a real type code, it is a fake number used for calling C# methods
public const byte VM = 255; // this isn't a real type code, it is used as a hack in calling C# methods
@@ -50,9 +50,9 @@ public static class TypeCodes
60, // dfloat
30, // void
30, // string (int ptr)
- 10, // ptr_reg
- 10, // ptr_heap
- 10, // struct (int ptr)
+ 100, // ptr_reg
+ 100, // ptr_heap
+ 100, // struct (int ptr)
};
public static readonly byte[] SIZE_TABLE = new byte[]
@@ -66,11 +66,11 @@ public static class TypeCodes
8, // dint
8, // dfloat
0, // void
- 4, // string (int ptr)
- 1, // ptr_reg
- 4, // ptr_heap
- 4, // struct (int ptr)
- 1, // global ptr_reg
+ 8, // string (int ptr)
+ 8, // ptr_reg
+ 8, // ptr_heap
+ 8, // struct (int ptr)
+ 8, // global ptr_reg
};
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -350,5 +350,11 @@ public static class OpCodes
/// The intersection of and
///
public const byte STORE_PTR_GLOBAL = 48;
+
+ ///
+ /// Similar to , but the value is actually a pointer
+ ///
+ public const byte LOAD_PTR_GLOBAL = 57;
+ public const byte LOAD_PTR = 58;
}
}
\ No newline at end of file
diff --git a/FadeBasic/FadeBasic/Virtual/VirtualMachine.cs b/FadeBasic/FadeBasic/Virtual/VirtualMachine.cs
index f53f884..85c39f8 100644
--- a/FadeBasic/FadeBasic/Virtual/VirtualMachine.cs
+++ b/FadeBasic/FadeBasic/Virtual/VirtualMachine.cs
@@ -40,7 +40,7 @@ public static bool IsPtr(byte flags)
public int[] insIndexes;
public byte[] flags;
- public VirtualScope(int initialCapacity)
+ public VirtualScope(ulong initialCapacity)
{
dataRegisters = new ulong[initialCapacity];
typeRegisters = new byte[initialCapacity];
@@ -105,18 +105,19 @@ public VirtualMachine(byte[] program)
{
this.program = program;
shouldThrowRuntimeException = true;
- globalScope = scope = new VirtualScope(256);
// scope = new VirtualScope(256);
scopeStack = new FastStack(16);
methodStack = new FastStack(16);
heap = new VmHeap(128);
- scopeStack.Push(globalScope);
instructionIndex = 4;
internedDataInstructionIndex = BitConverter.ToInt32(program, 0);
ReadInternedData();
+ globalScope = scope = new VirtualScope(internedData.maxRegisterAddress);
+ scopeStack.Push(globalScope);
+
// scopeStack.Push(scope);
}
@@ -149,8 +150,8 @@ public void Suspend()
///
public struct VmState
{
- public byte vTypeCode, typeCode, addr, size;
- public ulong data;
+ public byte vTypeCode, typeCode, size;
+ public ulong data, addr;
public int insPtr;
}
@@ -185,7 +186,7 @@ void ReadInternedData()
heap.AllocateString(size, out var ptr);
// this interned string should never be free'd, because we don't know when it will need to be accessed.
- heap.IncrementRefCount((ulong)ptr);
+ heap.IncrementRefCount(ptr);
var span = new byte[size];
for (var i = 0; i < str.value.Length; i++)
{
@@ -199,7 +200,7 @@ void ReadInternedData()
heap.Write(ptr, size, span);
- var ptrBytes = BitConverter.GetBytes(ptr);
+ var ptrBytes = VmPtr.GetBytes(ref ptr);
foreach (var index in str.indexReferences)
{
// replace the ptr starting at index with the actual assigned ptr
@@ -208,6 +209,11 @@ void ReadInternedData()
program[index + 3] = ptrBytes[1];
program[index + 4] = ptrBytes[2];
program[index + 5] = ptrBytes[3];
+
+ program[index + 6] = ptrBytes[4];
+ program[index + 7] = ptrBytes[5];
+ program[index + 8] = ptrBytes[6];
+ program[index + 9] = ptrBytes[7];
}
}
}
@@ -227,8 +233,8 @@ public void Execute2(int instructionBatchCount=1000)
// these pointer/data values need to be held between instruction evaluations, and therefor stay in the state.
byte vTypeCode = state.vTypeCode, typeCode = state.typeCode;
- ulong data = state.data;
- byte addr = state.addr, size = state.size;
+ ulong data = state.data, addr = state.addr;
+ byte size = state.size;
int insPtr = state.insPtr;
// var sw = new Stopwatch();
@@ -257,7 +263,7 @@ public void Execute2(int instructionBatchCount=1000)
break;
case OpCodes.PUSH_SCOPE:
- var newScope = new VirtualScope(64);
+ var newScope = new VirtualScope(internedData.maxRegisterAddress);
scopeStack.Push(newScope);
scope = newScope;
break;
@@ -276,7 +282,6 @@ public void Execute2(int instructionBatchCount=1000)
var ptr = vScope.dataRegisters[scopeIndex];
if (isPtr && vScope.insIndexes[scopeIndex] > 0)
{
-
heap.TryDecrementRefCount(ptr);
}
}
@@ -526,9 +531,9 @@ public void Execute2(int instructionBatchCount=1000)
VmUtil.PushSpan(ref stack, cSpan, TypeCodes.INT);
break;
case OpCodes.STORE:
-
// read a register location, which is always 1 byte.
- addr = Advance();
+ VmUtil.ReadRegAddress(program, ref instructionIndex, out addr);
+
VmUtil.ReadSpanAsUInt(ref stack, out data);
scope.dataRegisters[addr] = data;
scope.typeRegisters[addr] = typeCode;
@@ -539,7 +544,8 @@ public void Execute2(int instructionBatchCount=1000)
case OpCodes.STORE_PTR:
// read a register location, which is always 1 byte.
- addr = Advance();
+ VmUtil.ReadRegAddress(program, ref instructionIndex, out addr);
+
VmUtil.ReadSpanAsUInt(ref stack, out data);
if (scope.insIndexes[addr] > 0)
@@ -563,7 +569,8 @@ public void Execute2(int instructionBatchCount=1000)
case OpCodes.STORE_PTR_GLOBAL:
// read a register location, which is always 1 byte.
- addr = Advance();
+ VmUtil.ReadRegAddress(program, ref instructionIndex, out addr);
+
VmUtil.ReadSpanAsUInt(ref stack, out data);
if (globalScope.insIndexes[addr] > 0)
@@ -581,7 +588,7 @@ public void Execute2(int instructionBatchCount=1000)
break;
case OpCodes.STORE_GLOBAL:
- addr = Advance();
+ VmUtil.ReadRegAddress(program, ref instructionIndex, out addr);
VmUtil.ReadSpanAsUInt(ref stack, out data);
globalScope.dataRegisters[addr] = data;
globalScope.typeRegisters[addr] = typeCode;
@@ -590,7 +597,7 @@ public void Execute2(int instructionBatchCount=1000)
break;
case OpCodes.LOAD:
- addr = Advance();
+ VmUtil.ReadRegAddress(program, ref instructionIndex, out addr);
typeCode = scope.typeRegisters[addr];
data = scope.dataRegisters[addr];
@@ -598,9 +605,29 @@ public void Execute2(int instructionBatchCount=1000)
aBytes = BitConverter.GetBytes(data);
stack.PushSpanAndType(new ReadOnlySpan(aBytes), typeCode, size);
+ break;
+ case OpCodes.LOAD_PTR:
+ VmUtil.ReadRegAddress(program, ref instructionIndex, out addr);
+
+ typeCode = TypeCodes.PTR_HEAP;// globalScope.typeRegisters[addr];
+ data = scope.dataRegisters[addr];
+ size = TypeCodes.GetByteSize(typeCode);
+ aBytes = BitConverter.GetBytes(data);
+ stack.PushSpanAndType(new ReadOnlySpan(aBytes), typeCode, size);
+
+ break;
+ case OpCodes.LOAD_PTR_GLOBAL:
+ VmUtil.ReadRegAddress(program, ref instructionIndex, out addr);
+
+ typeCode = TypeCodes.PTR_HEAP;// globalScope.typeRegisters[addr];
+ data = globalScope.dataRegisters[addr];
+ size = TypeCodes.GetByteSize(typeCode);
+ aBytes = BitConverter.GetBytes(data);
+ stack.PushSpanAndType(new ReadOnlySpan(aBytes), typeCode, size);
+
break;
case OpCodes.LOAD_GLOBAL:
- addr = Advance();
+ VmUtil.ReadRegAddress(program, ref instructionIndex, out addr);
typeCode = globalScope.typeRegisters[addr];
data = globalScope.dataRegisters[addr];
@@ -619,8 +646,8 @@ public void Execute2(int instructionBatchCount=1000)
VmUtil.ReadAsInt(ref stack, out var allocLength);
heap.Allocate(ref format, allocLength, out var allocPtr);
// push the address onto the stack
- bBytes = BitConverter.GetBytes(allocPtr);
- VmUtil.PushSpan(ref stack, bBytes, TypeCodes.INT);
+ bBytes = VmPtr.GetBytes(ref allocPtr);
+ VmUtil.PushSpan(ref stack, bBytes, TypeCodes.PTR_HEAP);
break;
case OpCodes.DISCARD:
@@ -657,7 +684,7 @@ public void Execute2(int instructionBatchCount=1000)
break;
case OpCodes.READ:
- VmUtil.ReadAsInt(ref stack, out var readPtr);
+ VmUtil.ReadAsVmPtr(ref stack, out var readPtr);
VmUtil.ReadAsInt(ref stack, out var readLength);
heap.Read(readPtr, readLength, out aBytes);
stack.PushSpan(aBytes, readLength);
@@ -701,6 +728,8 @@ public void Execute2(int instructionBatchCount=1000)
}
+
+ public int test = 0;
void TriggerRuntimeError(VirtualRuntimeError error)
{
diff --git a/FadeBasic/FadeBasic/Virtual/VmHeap.cs b/FadeBasic/FadeBasic/Virtual/VmHeap.cs
index f099dfa..29dcf9e 100644
--- a/FadeBasic/FadeBasic/Virtual/VmHeap.cs
+++ b/FadeBasic/FadeBasic/Virtual/VmHeap.cs
@@ -1,82 +1,192 @@
using System;
using System.Collections.Generic;
+using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
namespace FadeBasic.Virtual
{
public struct VmAllocation
{
- public int ptr;
+ public VmPtr ptr;
public int length;
public HeapTypeFormat format;
}
+
+ ///
+ /// The max size of an array in C# is ~2 billion, or roughly 2^31. The 1 unused bit on the int isn't
+ /// useful enough to do much with.
+ ///
+ /// A ptr needs to be able to address more than 2^31 in a 64bit OS world.
+ /// A second integer is kept to add more bits, and acts as a way to bucketize the original 31 bit pointer.
+ ///
+ /// An object is not allowed to exceed the bucket size, which is 2^31 (C#'s addressable array size)
+ ///
+ public struct VmPtr : IEquatable
+ {
+
+
+ public static VmPtr operator +(VmPtr a, int b)
+ {
+ return new VmPtr
+ {
+ bucketPtr = a.bucketPtr,
+ memoryPtr = a.memoryPtr + b
+ };
+ }
+
+ public readonly static VmPtr TEMP = new VmPtr
+ {
+ bucketPtr = int.MaxValue, memoryPtr = int.MaxValue
+ };
+
+ public static VmPtr FromRaw(ulong raw)
+ {
+ var bytes = BitConverter.GetBytes(raw);
+ return FromBytes(bytes);
+ }
+
+ public static VmPtr FromBytes(ReadOnlySpan span) => FromBytes(span.ToArray());
+
+ public static VmPtr FromBytes(byte[] bytes)
+ {
+ // TODO: after all tests pass, flip the bytes around so that ptrs are more easily readable.
+ var ptr = new VmPtr
+ {
+ bucketPtr = BitConverter.ToInt32(bytes, 0),
+ memoryPtr = BitConverter.ToInt32(bytes, 4),
+ };
+
+ return ptr;
+ }
+
+ public static byte[] GetBytes(ref VmPtr ptr)
+ {
+ var bytes = new byte[sizeof(int) * 2];
+ var bucketBytes = BitConverter.GetBytes(ptr.bucketPtr);
+ var memoryBytes = BitConverter.GetBytes(ptr.memoryPtr);
+
+ for (var i = 0; i < bucketBytes.Length; i++)
+ {
+ bytes[i] = bucketBytes[i];
+ bytes[i + 4] = memoryBytes[i];
+ }
+
+ return bytes;
+ }
+
+
+ public static ulong GetRaw(ref VmPtr ptr)
+ {
+ return BitConverter.ToUInt64(GetBytes(ref ptr), 0);
+ }
+
+
+ // https://learn.microsoft.com/en-us/dotnet/api/system.array?view=net-9.0&redirectedfrom=MSDN#remarks
+ public const uint MAX_ARRAY_SIZE = 0X7FEFFFFF; // ~2 billion
+
+ public int bucketPtr;
+ public int memoryPtr;
+
+ public bool Equals(VmPtr other)
+ {
+ return bucketPtr == other.bucketPtr && memoryPtr == other.memoryPtr;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return obj is VmPtr other && Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ return (bucketPtr * 397) ^ memoryPtr;
+ }
+ }
+
+ public override string ToString()
+ {
+ return $"ptr(m={memoryPtr}, b={bucketPtr})";
+ }
+ }
+
+ public class HeapData : List
+ {
+ public int BucketSize(VmPtr ptr) => this[ptr.bucketPtr].Length;
+ }
public struct VmHeap
{
- public byte[] memory;
- private int _cursor;
+ // private byte[] memory;
+ private HeapData memory;
+ private VmPtr _cursor;
- public int Cursor => _cursor;
+ public VmPtr Cursor => _cursor;
///
/// key: a ptr
/// value: a length (and metadata)
///
/// If it exists in this dictionary, then it is "leased"
///
- private Dictionary _allocations;// = new Dictionary();
+ private Dictionary _allocations;// = new Dictionary();
- private Dictionary> _lengthToPtrs;// = new Dictionary>();
+ private Dictionary> _lengthToPtrs;// = new Dictionary>();
- private Dictionary _ptrToRefCount;
+ private Dictionary _ptrToRefCount;
public int Allocations => _allocations.Count;
public VmHeap(int initialCapacity)
{
- memory = new byte[initialCapacity];
- _cursor = 0;
- _allocations = new Dictionary();
- _lengthToPtrs = new Dictionary>();
- _ptrToRefCount = new Dictionary();
+ memory = new HeapData
+ {
+ new byte[initialCapacity]
+ };
+ _cursor = new VmPtr();
+ _allocations = new Dictionary();
+ _lengthToPtrs = new Dictionary>();
+ _ptrToRefCount = new Dictionary();
}
- public void Write(int ptr, int length, byte[] data)
+ public void Write(VmPtr ptr, int length, byte[] data)
{
for (var i = 0; i < length; i++)
{
- memory[ptr + i] = data[i];
+ memory[ptr.bucketPtr][ptr.memoryPtr + i] = data[i];
}
}
- public void WriteSpan(int ptr, int length, ReadOnlySpan data)
+ public void WriteSpan(VmPtr ptr, int length, ReadOnlySpan data)
{
- for (var i = 0; i < length; i++)
+ for (int i = 0; i < length; i++)
{
- memory[ptr + i] = data[i];
+ memory[ptr.bucketPtr][ptr.memoryPtr + i] = data[i];
}
}
- public void ReadSpan(int ptr, int length, out ReadOnlySpan memory)
+ public void ReadSpan(VmPtr ptr, int length, out ReadOnlySpan memory)
{
- memory = new ReadOnlySpan(this.memory, ptr, length);
+
+ memory = new ReadOnlySpan(this.memory[ptr.bucketPtr], ptr.memoryPtr, length);
}
- public void Read(int ptr, int length, out byte[] memory)
+ public void Read(VmPtr ptr, int length, out byte[] memory)
{
memory = new byte[length];
- for (var i = ptr; i < ptr + length; i++)
+ for (var i = ptr.memoryPtr; i < ptr.memoryPtr + length; i++)
{
// var memAddr = length - (i - ptr) - 1;
- var memAddr = i - ptr;
- memory[memAddr] = this.memory[i];
+ var memAddr = i - ptr.memoryPtr;
+ memory[memAddr] = this.memory[ptr.bucketPtr][i];
}
}
- public void Copy(int srcPtr, int dstPtr, int length)
+ public void Copy(VmPtr srcPtr, VmPtr dstPtr, int length)
{
for (var i = 0; i < length; i++)
{
- memory[dstPtr + i] = memory[srcPtr + i];
+ memory[dstPtr.bucketPtr][dstPtr.memoryPtr + i] = memory[srcPtr.bucketPtr][srcPtr.memoryPtr + i];
}
}
@@ -85,12 +195,12 @@ public void Copy(int srcPtr, int dstPtr, int length)
// var size = arrayLength * TypeCodes.GetByteSize(typeCode);
// Allocate(ref HeapTypeFormat.STRING_FORMAT, size, out ptr);
// }
- public void AllocateString(int length, out int ptr)
+ public void AllocateString(int length, out VmPtr ptr)
{
Allocate(ref HeapTypeFormat.STRING_FORMAT, length, out ptr);
}
- public void Free(int ptr)
+ public void Free(VmPtr ptr)
{
if (!_allocations.TryGetValue(ptr, out var allocation))
{
@@ -101,14 +211,15 @@ public void Free(int ptr)
// _ptrToFreed[ptr] = length;
if (!_lengthToPtrs.TryGetValue(allocation.length, out var ptrs))
{
- ptrs = _lengthToPtrs[allocation.length] = new Stack();
+ ptrs = _lengthToPtrs[allocation.length] = new Stack();
}
ptrs.Push(ptr);
}
- public void Allocate(ref HeapTypeFormat format, int size, out int ptr)
+ public void Allocate(ref HeapTypeFormat format, int size, out VmPtr ptr)
{
+ // TODO: assert that the size is less than the max array size.
// If there is something with the exact size we need, grab it!
if (_lengthToPtrs.TryGetValue(size, out var availablePtrs) && availablePtrs.Count > 0)
@@ -123,14 +234,34 @@ public void Allocate(ref HeapTypeFormat format, int size, out int ptr)
return;
}
- if (_cursor + size >= memory.Length)
+ if (_cursor.memoryPtr + size >= memory.BucketSize(_cursor))
{
-
-
-
- while (_cursor + size >= memory.Length)
+ if (_cursor.memoryPtr + size >= memory.BucketSize(_cursor) && (uint)_cursor.memoryPtr + (uint)size >= VmPtr.MAX_ARRAY_SIZE)
{
- Array.Resize(ref memory, memory.Length * 2);
+ // game over! We need a new bucket!
+ _cursor.bucketPtr += 1;
+ _cursor.memoryPtr = 0;
+
+ // allocate the next bucket at the full size, since we've exhausted one anyway...
+ // this does mean that the program mem jumps from 2GB to 4GB. You cannot have
+ // 3GB working set :(
+ memory.Add(new byte[VmPtr.MAX_ARRAY_SIZE]);
+
+ }
+ else
+ {
+ // expand the current bucket size
+ while (_cursor.memoryPtr + size >= memory.BucketSize(_cursor))
+ {
+ var nextSize = (uint)memory.BucketSize(_cursor) * 2;
+ if (nextSize >= VmPtr.MAX_ARRAY_SIZE)
+ {
+ nextSize = VmPtr.MAX_ARRAY_SIZE;
+ }
+ var arr = memory[_cursor.bucketPtr];
+ Array.Resize(ref arr, (int)nextSize);
+ memory[_cursor.bucketPtr] = arr;
+ }
}
}
@@ -144,15 +275,15 @@ public void Allocate(ref HeapTypeFormat format, int size, out int ptr)
};
if (size == 0)
{
- _cursor += 1; // increase the cursor by 1, so that this spot is held as "empty"
+ _cursor.memoryPtr += 1; // increase the cursor by 1, so that this spot is held as "empty"
}
else
{
- _cursor += size;
+ _cursor.memoryPtr += size;
}
}
- public void GetAllocationSize(int ptr, out int size)
+ public void GetAllocationSize(VmPtr ptr, out int size)
{
if (!_allocations.TryGetValue(ptr, out var allocation))
{
@@ -161,28 +292,28 @@ public void GetAllocationSize(int ptr, out int size)
size = allocation.length;
}
- public bool TryGetAllocationSize(int ptr, out int size)
+ public bool TryGetAllocationSize(VmPtr ptr, out int size)
{
var success = _allocations.TryGetValue(ptr, out var allocation);
size = allocation.length;
return success;
}
- public bool TryGetAllocation(int ptr, out VmAllocation allocation)
+ public bool TryGetAllocation(VmPtr ptr, out VmAllocation allocation)
{
return _allocations.TryGetValue(ptr, out allocation);
}
- public void IncrementRefCount(ulong ptr)
+ public void IncrementRefCount(ulong ptr) => IncrementRefCount(VmPtr.FromRaw(ptr));
+ public void IncrementRefCount(VmPtr ptr)
{
- var key = (int)ptr;
- if (_ptrToRefCount.TryGetValue(key, out var refCount))
+ if (_ptrToRefCount.TryGetValue(ptr, out var refCount))
{
- _ptrToRefCount[key] = refCount + 1;
+ _ptrToRefCount[ptr] = refCount + 1;
}
else
{
- _ptrToRefCount[key] = 1;
+ _ptrToRefCount[ptr] = 1;
}
}
@@ -206,14 +337,14 @@ public void Sweep()
// }
// }
}
-
- public void TryDecrementRefCount(ulong ptr)
- {
- var key = (int)ptr;
- if (_ptrToRefCount.TryGetValue(key, out var refCount))
+ public void TryDecrementRefCount(ulong ptr) => TryDecrementRefCount(VmPtr.FromRaw(ptr));
+
+ public void TryDecrementRefCount(VmPtr ptr)
+ {
+ if (_ptrToRefCount.TryGetValue(ptr, out var refCount))
{
- _ptrToRefCount[key] = refCount - 1;
+ _ptrToRefCount[ptr] = refCount - 1;
if (refCount == 1)
{
diff --git a/FadeBasic/FadeBasic/Virtual/VmUtil.cs b/FadeBasic/FadeBasic/Virtual/VmUtil.cs
index 60d92d0..7638949 100644
--- a/FadeBasic/FadeBasic/Virtual/VmUtil.cs
+++ b/FadeBasic/FadeBasic/Virtual/VmUtil.cs
@@ -127,12 +127,18 @@ public static byte GetTypeCode(VariableType vt)
}
}
+ public static VmPtr ConvertToPtr(ulong rawValue)
+ {
+ return VmPtr.FromRaw(rawValue);
+ }
+
public static int ConvertToInt(ulong rawValue)
{
var outputRegisterBytes = BitConverter.GetBytes(rawValue);
int output = BitConverter.ToInt32(outputRegisterBytes, 0);
return output;
}
+
public static float ConvertToFloat(ulong rawValue)
{
var outputRegisterBytes = BitConverter.GetBytes(rawValue);
@@ -172,27 +178,6 @@ public static double ConvertToDFloat(ulong rawValue)
return BitConverter.ToDouble(outputRegisterBytes, 0);
}
- public static string GetTypeName(byte typeCode, VirtualMachine vm, ulong rawValue)
- {
- if (!VmUtil.TryGetVariableTypeDisplay(typeCode, out var typeName))
- {
- return "UNKNOWN";
- }
-
- if (typeCode == TypeCodes.STRUCT)
- {
- // the rawValue is a ptr into the heap...
- if (vm.heap.TryGetAllocation((int) rawValue, out var allocation))
- {
- var typeId = allocation.format.typeId;
- var type = vm.typeTable[typeId];
- typeName = type.name;
- }
- }
-
- return typeName;
- }
-
public static string ConvertValueToDisplayString(byte typeCode, VirtualMachine vm, ref ReadOnlySpan span)
{
switch (typeCode)
@@ -216,7 +201,7 @@ public static string ConvertValueToDisplayString(byte typeCode, VirtualMachine v
var num2 = BitConverter.ToDouble(span.ToArray(), 0);
return num2.ToString(CultureInfo.InvariantCulture);
case TypeCodes.STRING:
- var address = BitConverter.ToInt32(span.ToArray(), 0);
+ var address = VmPtr.FromBytes(span.ToArray());
if (vm.heap.TryGetAllocationSize(address, out var strSize))
{
vm.heap.Read(address, strSize, out var strBytes);
@@ -264,7 +249,7 @@ public static void GetBytes(T value, out byte[] bytes)
throw new NotImplementedException("cannot convert unknown type to bytes " + value + " typeof " + typeof(T));
}
}
- public static void HandleValue(VirtualMachine vm, T value, byte typeCode, CommandArgRuntimeState state, int address) where T : struct
+ public static void HandleValue(VirtualMachine vm, T value, byte typeCode, CommandArgRuntimeState state, ulong address) where T : struct
{
switch (state)
{
@@ -279,7 +264,8 @@ public static void HandleValue(VirtualMachine vm, T value, byte typeCode, Com
case CommandArgRuntimeState.HeapRef:
var size = TypeCodes.GetByteSize(typeCode);
GetBytes(value, out var heapBytes);
- vm.heap.Write(address, size, heapBytes);
+ var ptrAddr = VmPtr.FromRaw(address);
+ vm.heap.Write(ptrAddr, size, heapBytes);
break;
case CommandArgRuntimeState.Value:
// do nothing.
@@ -288,17 +274,17 @@ public static void HandleValue(VirtualMachine vm, T value, byte typeCode, Com
}
- public static void HandleValueString(VirtualMachine vm, string value, byte typeCode, CommandArgRuntimeState state, int address)
+ public static void HandleValueString(VirtualMachine vm, string value, byte typeCode, CommandArgRuntimeState state, ulong address)
{
byte[] strBytes;
- int strPtr;
+ VmPtr strPtr;
switch (state)
{
case CommandArgRuntimeState.RegisterRef:
VmConverter.FromString(value, out strBytes);
vm.heap.Allocate(ref HeapTypeFormat.STRING_FORMAT, strBytes.Length, out strPtr);
vm.heap.Write(strPtr, strBytes.Length, strBytes);
- vm.dataRegisters[address] = BitConverter.ToUInt32(BitConverter.GetBytes(strPtr), 0);
+ vm.dataRegisters[address] = VmPtr.GetRaw(ref strPtr);
vm.typeRegisters[address] = typeCode;
break;
case CommandArgRuntimeState.HeapRef:
@@ -306,7 +292,7 @@ public static void HandleValueString(VirtualMachine vm, string value, byte typeC
VmConverter.FromString(value, out strBytes);
vm.heap.Allocate(ref HeapTypeFormat.STRING_FORMAT,strBytes.Length, out strPtr);
vm.heap.Write(strPtr, strBytes.Length, strBytes);
- vm.heap.Write(address, 4, BitConverter.GetBytes(strPtr));
+ vm.heap.Write(VmPtr.FromRaw(address), 8, VmPtr.GetBytes(ref strPtr));
break;
case CommandArgRuntimeState.Value:
// do nothing.
@@ -317,10 +303,11 @@ public static void HandleValueString(VirtualMachine vm, string value, byte typeC
// public static void ReadValue(VirtualMachine vm, string defaultValue, out string )
public static void ReadValueString(VirtualMachine vm, string defaultValue, out string value,
- out CommandArgRuntimeState state, out int address)
+ out CommandArgRuntimeState state, out ulong address)
{
ReadSpan(ref vm.stack, out var typeCode, out var span);
- int strPtr = 0, strSize = 0;
+ int strSize = 0;
+ VmPtr strPtr = default;
switch (typeCode)
{
case TypeCodes.VOID:
@@ -330,12 +317,11 @@ public static void ReadValueString(VirtualMachine vm, string defaultValue, out s
break;
case TypeCodes.PTR_REG:
state = CommandArgRuntimeState.RegisterRef;
- address = (int) span[0];
+ address = MemoryMarshal.Read(span);
var data = vm.dataRegisters[address];
typeCode = vm.typeRegisters[address];
// TODO: we could validate that typeCode is equal to the given typeCode for
- var bytes = BitConverter.GetBytes(data);
- strPtr = (int)BitConverter.ToUInt32(bytes, 0);
+ strPtr = VmPtr.FromRaw(data);
if (vm.heap.TryGetAllocationSize(strPtr, out strSize))
{
vm.heap.Read(strPtr, strSize, out var strBytes);
@@ -348,12 +334,11 @@ public static void ReadValueString(VirtualMachine vm, string defaultValue, out s
break;
case TypeCodes.PTR_GLOBAL_REG:
state = CommandArgRuntimeState.GlobalRegisterRef;
- address = (int) span[0];
+ address = MemoryMarshal.Read(span);
data = vm.globalScope.dataRegisters[address];
typeCode = vm.globalScope.typeRegisters[address];
// TODO: we could validate that typeCode is equal to the given typeCode for
- bytes = BitConverter.GetBytes(data);
- strPtr = (int)BitConverter.ToUInt32(bytes, 0);
+ strPtr = VmPtr.FromRaw(data);
if (vm.heap.TryGetAllocationSize(strPtr, out strSize))
{
vm.heap.Read(strPtr, strSize, out var strBytes);
@@ -366,12 +351,13 @@ public static void ReadValueString(VirtualMachine vm, string defaultValue, out s
break;
case TypeCodes.PTR_HEAP:
state = CommandArgRuntimeState.HeapRef;
- address = MemoryMarshal.Read(span);
+ address = MemoryMarshal.Read(span);
// the heap does not store type info, which means we need to assume the next value on the stack is the type code.
typeCode = vm.stack.Pop();
- if (vm.heap.TryGetAllocationSize(address, out strSize))
+ var ptrAddress = VmPtr.FromRaw(address);
+ if (vm.heap.TryGetAllocationSize(ptrAddress, out strSize))
{
- vm.heap.Read(address, strSize, out var strBytes);
+ vm.heap.Read(ptrAddress, strSize, out var strBytes);
value = VmConverter.ToString(strBytes);
}
else
@@ -383,7 +369,9 @@ public static void ReadValueString(VirtualMachine vm, string defaultValue, out s
default:
state = CommandArgRuntimeState.Value;
address = 0;
- strPtr = MemoryMarshal.Read(span);
+ var rawData = MemoryMarshal.Read(span);
+ // strPtr = MemoryMarshal.Read(span);
+ strPtr = VmPtr.FromRaw(rawData);
if (vm.heap.TryGetAllocationSize(strPtr, out strSize))
{
vm.heap.Read(strPtr, strSize, out var strBytes);
@@ -397,7 +385,7 @@ public static void ReadValueString(VirtualMachine vm, string defaultValue, out s
}
}
- public static void ReadValue(VirtualMachine vm, T defaultValue, out T value, out CommandArgRuntimeState state, out int address) where T : struct
+ public static void ReadValue(VirtualMachine vm, T defaultValue, out T value, out CommandArgRuntimeState state, out ulong address) where T : struct
{
ReadSpan(ref vm.stack, out var typeCode, out var span);
switch (typeCode)
@@ -409,7 +397,7 @@ public static void ReadValue(VirtualMachine vm, T defaultValue, out T value,
break;
case TypeCodes.PTR_REG:
state = CommandArgRuntimeState.RegisterRef;
- address = (int) span[0];
+ address = MemoryMarshal.Read(span);
var data = vm.dataRegisters[address];
typeCode = vm.typeRegisters[address];
var bytes = BitConverter.GetBytes(data);
@@ -417,7 +405,7 @@ public static void ReadValue(VirtualMachine vm, T defaultValue, out T value,
break;
case TypeCodes.PTR_GLOBAL_REG:
state = CommandArgRuntimeState.GlobalRegisterRef;
- address = (int) span[0];
+ address = MemoryMarshal.Read(span);
data = vm.globalScope.dataRegisters[address];
typeCode = vm.globalScope.typeRegisters[address];
bytes = BitConverter.GetBytes(data);
@@ -425,7 +413,7 @@ public static void ReadValue(VirtualMachine vm, T defaultValue, out T value,
break;
case TypeCodes.PTR_HEAP:
state = CommandArgRuntimeState.HeapRef;
- address = MemoryMarshal.Read(span);
+ address = MemoryMarshal.Read(span);
// the heap does not store type info, which means we need to assume the next value on the stack is the type code.
typeCode = vm.stack.Pop();
@@ -435,7 +423,7 @@ public static void ReadValue(VirtualMachine vm, T defaultValue, out T value,
{
var size = TypeCodes.GetByteSize(typeCode);
// vm.heap.Read(address, size, out bytes);
- vm.heap.ReadSpan(address, size, out span);
+ vm.heap.ReadSpan(VmPtr.FromRaw(address), size, out span);
}
value = MemoryMarshal.Read(span);
@@ -449,7 +437,7 @@ public static void ReadValue(VirtualMachine vm, T defaultValue, out T value,
}
- public static void ReadValueAny(VirtualMachine vm, object defaultValue, out object value, out CommandArgRuntimeState state, out int address)
+ public static void ReadValueAny(VirtualMachine vm, object defaultValue, out object value, out CommandArgRuntimeState state, out ulong address)
{
// peek the type code...
var peekTypeCode = vm.stack.Peek();
@@ -497,44 +485,37 @@ public static void WriteToHeap(ref FastStack stack, ref VmHeap heap, bool
{
// ReadAsInt(stack, out var writePtr);
var typeCode = stack.Pop();
- if (typeCode != TypeCodes.INT)
+ if (typeCode != TypeCodes.PTR_HEAP && typeCode != TypeCodes.STRUCT) // TODO: this used to say INT. Maybe it needs to also allow STRING?
{
- throw new Exception("vm exception: expected an int for ptr");
+ throw new Exception("vm exception: expected ptr");
}
- ReadSpan(ref stack, TypeCodes.INT, out var aSpan);
+ ReadSpan(ref stack, TypeCodes.PTR_HEAP, out var aSpan);
- // Read(stack, TypeCodes.INT, out var aBytes);
- var writePtr = BitConverter.ToInt32(aSpan.ToArray(), 0);
+ var writePtr = VmPtr.FromBytes(aSpan);
ReadAsInt(ref stack, out var writeLength);
// var bytes = new byte[writeLength];
stack.PopArraySpan(writeLength, out var span);
- /*
- * In the old system, this just happened to work by accident.
- * but the issue is that the stack has 3,0,0,0 on it,
- * but the write-length is set to the size of the entry, which is 2.
- * so the write-length only finds 0,0 instead of 0,3
- *
- * Or I guess, we could CAST the type to the desired type...
- */
-
- // for (var w = 0; w < writeLength; w++)
- // {
- // var b = stack.Pop();
- // bytes[w] = b;
- // }
-
- //heap.Write(writePtr, writeLength, span.ToArray());
heap.WriteSpan(writePtr, writeLength, span);
if (pushPtr)
{
- PushSpan(ref stack, aSpan, TypeCodes.INT);
- // Push(stack, aBytes, TypeCodes.INT);
+ PushSpan(ref stack, aSpan, TypeCodes.PTR_HEAP);
+ }
+ }
+
+ public static void ReadAsVmPtr(ref FastStack stack, out VmPtr result)
+ {
+ var typeCode = stack.Pop();
+ if (typeCode != TypeCodes.PTR_HEAP && typeCode != TypeCodes.STRUCT) // TODO: does this also need to include string?
+ {
+ throw new Exception("vm exception: expected a ptr");
}
+ ReadSpan(ref stack, TypeCodes.PTR_HEAP, out var span);
+ result = VmPtr.FromBytes(span);
}
public static void ReadAsInt(ref FastStack stack, out int result)
@@ -911,8 +892,8 @@ public static void EqualTo(ref FastStack stack, ref VmHeap heap, byte aTyp
// read the data at a
// VmUtil.ReadAsInt();
- var aPtr = BitConverter.ToInt32(a, 0);
- var bPtr = BitConverter.ToInt32(b, 0);
+ var aPtr = VmPtr.FromBytes(a);
+ var bPtr = VmPtr.FromBytes(b);
heap.GetAllocationSize(aPtr, out var aSize);
heap.GetAllocationSize(bPtr, out var bSize);
@@ -1242,13 +1223,31 @@ public static void Add(ref VmHeap heap, byte aTypeCode, ReadOnlySpan aSpan
byte[] b = bSpan.ToArray();
switch (aTypeCode)
{
+ case TypeCodes.STRUCT:
+ case TypeCodes.PTR_HEAP:
+ var ptrA = VmPtr.FromBytes(a);
+ var ptrB = VmPtr.FromBytes(b);
+ if (ptrA.bucketPtr != 0)
+ {
+ // the second pointer must always have a zero bucket, because the final pointer must be
+ // in the same bucket as the first pointer.
+ throw new InvalidOperationException("cannot add pointer buckets");
+ }
+
+ var ptrC = new VmPtr
+ {
+ bucketPtr = ptrA.bucketPtr,
+ memoryPtr = ptrA.memoryPtr + ptrB.memoryPtr
+ };
+ c = VmPtr.GetBytes(ref ptrC);
+ break;
case TypeCodes.STRING:
/*
* two pointers; we need to allocate a new string for the sum of the lengths;
* then array copy the two strings into their respective positions
*/
- var aPtr = BitConverter.ToInt32(a, 0);
- var bPtr = BitConverter.ToInt32(b, 0);
+ var aPtr = VmPtr.FromBytes(a);
+ var bPtr = VmPtr.FromBytes(b);
heap.GetAllocationSize(aPtr, out var aLength);
heap.GetAllocationSize(bPtr, out var bLength);
var sumLength = aLength + bLength;
@@ -1259,7 +1258,7 @@ public static void Add(ref VmHeap heap, byte aTypeCode, ReadOnlySpan aSpan
heap.Copy(bPtr, sumPtr, bLength);
heap.Copy(aPtr, sumPtr + bLength, aLength);
- c = BitConverter.GetBytes(sumPtr);
+ c = VmPtr.GetBytes(ref sumPtr);
break;
case TypeCodes.BOOL:
case TypeCodes.BYTE:
@@ -1402,8 +1401,13 @@ public static void CastInlineSpan(ReadOnlySpan span, byte currentTypeCode,
case TypeCodes.PTR_HEAP:
case TypeCodes.STRUCT:
case TypeCodes.STRING:
- // a string type IS just an int ptr; so we don't need to convert anything!
- outputSpan = span;
+ // assume that int pointers are all in the same bucket
+ var mem = BitConverter.ToInt32(span.ToArray(), 0);
+ var ptr = new VmPtr
+ {
+ memoryPtr = mem
+ };
+ outputSpan = VmPtr.GetBytes(ref ptr);
break;
default:
throw new NotImplementedException($"cast from int to typeCode=[{typeCode}] is not supported yet.");
@@ -1525,13 +1529,32 @@ public static void CastInlineSpan(ReadOnlySpan span, byte currentTypeCode,
case TypeCodes.STRUCT:
switch (typeCode)
{
- case TypeCodes.INT:
+ case TypeCodes.PTR_HEAP:
outputSpan = span;
break;
default:
throw new NotImplementedException($"cast from struct ptr to typeCode=[{typeCode}] is not supported yet.");
}
+ break;
+ case TypeCodes.PTR_HEAP:
+ switch (typeCode)
+ {
+ // case TypeCodes.INT:
+ // var intVersion = BitConverter.ToInt32(span.ToArray(), 0);
+ // var ptr = new VmPtr
+ // {
+ // memoryPtr = intVersion
+ // };
+ // outputSpan = VmPtr.GetBytes(ref ptr);
+ // break;
+ case TypeCodes.STRUCT:
+ case TypeCodes.STRING:
+ outputSpan = span;
+ break;
+ default:
+ throw new NotImplementedException($"cast from ptr to typeCode=[{typeCode}] is not supported yet.");
+ }
break;
default:
throw new NotImplementedException($"casts from typeCode=[{currentTypeCode}] types are not supported. target=[{typeCode}]");
@@ -1618,5 +1641,11 @@ public static void GetMinMax(byte aTypeCode, ReadOnlySpan aSpan, ReadOnlyS
throw new Exception("Unsupported add operation");
}
}
+
+ public static void ReadRegAddress(byte[] program, ref int instructionIndex, out ulong addr)
+ {
+ addr = BitConverter.ToUInt64(program, instructionIndex);
+ instructionIndex += sizeof(ulong);
+ }
}
}
\ No newline at end of file
diff --git a/FadeBasic/FadeCommandsViaNuget/FadeCommandsViaNuget.csproj b/FadeBasic/FadeCommandsViaNuget/FadeCommandsViaNuget.csproj
index ac5f981..cbfb958 100644
--- a/FadeBasic/FadeCommandsViaNuget/FadeCommandsViaNuget.csproj
+++ b/FadeBasic/FadeCommandsViaNuget/FadeCommandsViaNuget.csproj
@@ -5,7 +5,7 @@
enable
enable
$(FADE_NUGET_VERSION)
- 0.13.12.293
+ 0.12.13.305
diff --git a/FadeBasic/Tests/DebuggerTests.cs b/FadeBasic/Tests/DebuggerTests.cs
index 01517bc..d84f885 100644
--- a/FadeBasic/Tests/DebuggerTests.cs
+++ b/FadeBasic/Tests/DebuggerTests.cs
@@ -380,7 +380,7 @@ public async Task DebugServerTest()
session.StartDebugging(2); // read the message (1 op for the read, and 1 op to move the debugger forward)
await Task.Delay(100); // fluff time for the ack to emit
Assert.That(receivedConf, Is.True);
- Assert.That(session.InstructionPointer, Is.EqualTo(20),
+ Assert.That(session.InstructionPointer, Is.EqualTo(27),
"The debugger should be paused, so the insptr should not have moved from last time.");
}
diff --git a/FadeBasic/Tests/Fixtures/Projects/UsesProject/usesProject.csproj b/FadeBasic/Tests/Fixtures/Projects/UsesProject/usesProject.csproj
index feab418..5b4860e 100644
--- a/FadeBasic/Tests/Fixtures/Projects/UsesProject/usesProject.csproj
+++ b/FadeBasic/Tests/Fixtures/Projects/UsesProject/usesProject.csproj
@@ -3,7 +3,7 @@
net8.0
Exe
$(FADE_NUGET_VERSION)
- 0.13.12.293
+ 0.12.13.305
diff --git a/FadeBasic/Tests/FunctionVmTests.cs b/FadeBasic/Tests/FunctionVmTests.cs
index 2fe548d..ec13337 100644
--- a/FadeBasic/Tests/FunctionVmTests.cs
+++ b/FadeBasic/Tests/FunctionVmTests.cs
@@ -227,7 +227,7 @@ EndFunction a + ""hello""
var vm = new VirtualMachine(prog);
vm.Execute2();
- vm.heap.Read((int)vm.dataRegisters[0], "worldhello".Length * 4, out var memory);
+ vm.heap.Read(vm.dataRegisters[0].ToPtr(), "worldhello".Length * 4, out var memory);
var str = VmConverter.ToString(memory);
Assert.That(str, Is.EqualTo("worldhello"));
@@ -251,7 +251,7 @@ EndFunction a$
var vm = new VirtualMachine(prog);
vm.Execute2();
- vm.heap.Read((int)vm.dataRegisters[0], "hello".Length * 4, out var memory);
+ vm.heap.Read(vm.dataRegisters[0].ToPtr(), "hello".Length * 4, out var memory);
var str = VmConverter.ToString(memory);
Assert.That(str, Is.EqualTo("hello"));
@@ -288,15 +288,15 @@ EndFunction e
var vm = new VirtualMachine(prog);
vm.Execute2();
- Assert.That(vm.heap.Cursor, Is.EqualTo(4 * 3)); // size of the only field in egg, int, 4. And there are 3 copies; one in global scope, one passed to the function, and one returned from the function
+ Assert.That(vm.heap.Cursor, Is.EqualTo((4 * 3).ToPtr())); // size of the only field in egg, int, 4. And there are 3 copies; one in global scope, one passed to the function, and one returned from the function
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.STRUCT));
- vm.heap.Read((int)vm.dataRegisters[0], 4, out var memory);
+ vm.heap.Read(vm.dataRegisters[0].ToPtr(), 4, out var memory);
var data = BitConverter.ToInt32(memory);
Assert.That(data, Is.EqualTo(1));
Assert.That(vm.typeRegisters[1], Is.EqualTo(TypeCodes.STRUCT));
- vm.heap.Read((int)vm.dataRegisters[1], 4, out memory);
+ vm.heap.Read(vm.dataRegisters[1].ToPtr(), 4, out memory);
data = BitConverter.ToInt32(memory);
Assert.That(data, Is.EqualTo(6));
}
@@ -436,8 +436,8 @@ EndFunction returnValue$
// at this point, the pointer to the right heap is getting lost???
var expected = "the eight of pie";
- vm.heap.GetAllocationSize((int)vm.dataRegisters[0], out var allocSize);
- vm.heap.Read((int)vm.dataRegisters[0], allocSize, out var memory);
+ vm.heap.GetAllocationSize(vm.dataRegisters[0].ToPtr(), out var allocSize);
+ vm.heap.Read(vm.dataRegisters[0].ToPtr(), allocSize, out var memory);
var str = VmConverter.ToString(memory);
Assert.That(str, Is.EqualTo(expected));
@@ -472,11 +472,11 @@ EndFunction a.x + a.y
var vm = new VirtualMachine(prog);
vm.Execute().MoveNext();
- vm.heap.Read((int)vm.dataRegisters[0], 4, out var memory);
+ vm.heap.Read(vm.dataRegisters[0].ToPtr(), 4, out var memory);
var data = BitConverter.ToInt32(memory);
Assert.That(data, Is.EqualTo(32));
- vm.heap.Read((int)vm.dataRegisters[0] + 4, 4, out memory);
+ vm.heap.Read(vm.dataRegisters[0].ToPtr() + 4, 4, out memory);
data = BitConverter.ToInt32(memory);
Assert.That(data, Is.EqualTo(66));
@@ -513,11 +513,11 @@ Function Test(a as egg)
var vm = new VirtualMachine(prog);
vm.Execute().MoveNext();
- vm.heap.Read((int)vm.dataRegisters[0], 4, out var memory);
+ vm.heap.Read(vm.dataRegisters[0].ToPtr(), 4, out var memory);
var data = BitConverter.ToInt32(memory);
Assert.That(data, Is.EqualTo(32));
- vm.heap.Read((int)vm.dataRegisters[0] + 4, 4, out memory);
+ vm.heap.Read(vm.dataRegisters[0].ToPtr() + 4, 4, out memory);
data = BitConverter.ToInt32(memory);
Assert.That(data, Is.EqualTo(66));
diff --git a/FadeBasic/Tests/TestExtensions.cs b/FadeBasic/Tests/TestExtensions.cs
new file mode 100644
index 0000000..6e23756
--- /dev/null
+++ b/FadeBasic/Tests/TestExtensions.cs
@@ -0,0 +1,14 @@
+using FadeBasic.Virtual;
+
+namespace Tests;
+
+public static class TestExtensions
+{
+ public static VmPtr ToPtr(this ulong raw) => VmPtr.FromRaw(raw);
+
+ public static VmPtr ToPtr(this int raw) => new VmPtr
+ {
+ bucketPtr = 0,
+ memoryPtr = raw
+ };
+}
\ No newline at end of file
diff --git a/FadeBasic/Tests/TokenVm.cs b/FadeBasic/Tests/TokenVm.cs
index fb18360..b012216 100644
--- a/FadeBasic/Tests/TokenVm.cs
+++ b/FadeBasic/Tests/TokenVm.cs
@@ -150,18 +150,18 @@ public void String_Init_StartEmpty()
Assert.That(vm.dataRegisters[0], Is.EqualTo(0)); // the ptr to the string in memory
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.STRING));
- Assert.That(vm.dataRegisters[1], Is.EqualTo(1)); // the ptr to the string in memory
+ Assert.That(vm.dataRegisters[1].ToPtr(), Is.EqualTo(1.ToPtr())); // the ptr to the string in memory
Assert.That(vm.typeRegisters[1], Is.EqualTo(TypeCodes.STRING));
Assert.That(vm.typeRegisters[2], Is.EqualTo(TypeCodes.INT));
Assert.That(vm.dataRegisters[2], Is.EqualTo(0)); // zero length string
- vm.heap.Read((int)vm.dataRegisters[0], "".Length * 4, out var memory);
+ vm.heap.Read(vm.dataRegisters[0].ToPtr(), "".Length * 4, out var memory);
var str = VmConverter.ToString(memory);
Assert.That(str, Is.EqualTo(""));
- vm.heap.Read((int)vm.dataRegisters[1], "a".Length * 4, out memory);
+ vm.heap.Read(vm.dataRegisters[1].ToPtr(), "a".Length * 4, out memory);
str = VmConverter.ToString(memory);
Assert.That(str, Is.EqualTo("a"));
@@ -183,16 +183,16 @@ public void String_Concat()
Assert.That(vm.dataRegisters[0], Is.EqualTo(0)); // the ptr to the string in memory
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.STRING));
- vm.heap.Read((int)vm.dataRegisters[0], "hello".Length * 4, out var memory);
+ vm.heap.Read(vm.dataRegisters[0].ToPtr(), "hello".Length * 4, out var memory);
var str = VmConverter.ToString(memory);
Assert.That(str, Is.EqualTo("hello"));
- vm.heap.Read((int)vm.dataRegisters[1], "world".Length * 4, out memory);
+ vm.heap.Read(vm.dataRegisters[1].ToPtr(), "world".Length * 4, out memory);
str = VmConverter.ToString(memory);
Assert.That(str, Is.EqualTo("world"));
- vm.heap.Read((int)vm.dataRegisters[2], "helloworld".Length * 4, out memory);
+ vm.heap.Read(vm.dataRegisters[2].ToPtr(), "helloworld".Length * 4, out memory);
str = VmConverter.ToString(memory);
Assert.That(str, Is.EqualTo("helloworld"));
}
@@ -210,10 +210,10 @@ public void String_Concat_SelfReference()
var vm = new VirtualMachine(prog);
vm.Execute2();
- Assert.That(vm.dataRegisters[0], Is.EqualTo("world".Length * 4 + "hello ".Length * 4)); // the ptr to the string in memory
+ Assert.That(vm.dataRegisters[0].ToPtr(), Is.EqualTo(("world".Length * 4 + "hello ".Length * 4).ToPtr())); // the ptr to the string in memory
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.STRING));
- vm.heap.Read((int)vm.dataRegisters[0], "hello world".Length * 4, out var memory);
+ vm.heap.Read(vm.dataRegisters[0].ToPtr(), "hello world".Length * 4, out var memory);
var str = VmConverter.ToString(memory);
Assert.That(str, Is.EqualTo("hello world"));
@@ -243,11 +243,11 @@ public void String_Concat_VariableAndLiteral()
Assert.That(vm.dataRegisters[0], Is.EqualTo(0)); // the ptr to the string in memory
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.STRING));
- vm.heap.Read((int)vm.dataRegisters[0], "hello".Length * 4, out var memory);
+ vm.heap.Read(vm.dataRegisters[0].ToPtr(), "hello".Length * 4, out var memory);
var str = VmConverter.ToString(memory);
Assert.That(str, Is.EqualTo("hello"));
- vm.heap.Read((int)vm.dataRegisters[1], "hello world".Length * 4, out memory);
+ vm.heap.Read(vm.dataRegisters[1].ToPtr(), "hello world".Length * 4, out memory);
str = VmConverter.ToString(memory);
Assert.That(str, Is.EqualTo("hello world"));
@@ -269,11 +269,11 @@ public void String_Concat_LiteralAndVariable()
Assert.That(vm.dataRegisters[0], Is.EqualTo(0)); // the ptr to the string in memory
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.STRING));
- vm.heap.Read((int)vm.dataRegisters[0], "hello".Length * 4, out var memory);
+ vm.heap.Read(vm.dataRegisters[0].ToPtr(), "hello".Length * 4, out var memory);
var str = VmConverter.ToString(memory);
Assert.That(str, Is.EqualTo("hello"));
- vm.heap.Read((int)vm.dataRegisters[1], "helloworld".Length * 4, out memory);
+ vm.heap.Read(vm.dataRegisters[1].ToPtr(), "helloworld".Length * 4, out memory);
str = VmConverter.ToString(memory);
Assert.That(str, Is.EqualTo("worldhello"));
@@ -292,7 +292,7 @@ public void String_Declare2_WithIncrementalEval()
Assert.That(vm.dataRegisters[1], Is.EqualTo(0)); // the ptr to the string in memory
Assert.That(vm.typeRegisters[1], Is.EqualTo(TypeCodes.STRING));
- vm.heap.Read(0, "hello".Length * 4, out var memory);
+ vm.heap.Read(0.ToPtr(), "hello".Length * 4, out var memory);
var str = VmConverter.ToString(memory);
Assert.That(str, Is.EqualTo("hello"));
@@ -310,7 +310,7 @@ public void String_Declare()
Assert.That(vm.dataRegisters[0], Is.EqualTo(0)); // the ptr to the string in memory
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.STRING));
- vm.heap.Read(0, "hello".Length * 4, out var memory);
+ vm.heap.Read(0.ToPtr(), "hello".Length * 4, out var memory);
var str = VmConverter.ToString(memory);
Assert.That(str, Is.EqualTo("hello"));
@@ -349,7 +349,7 @@ public void String_Declare_HugeHeap()
Assert.That(vm.dataRegisters[0], Is.EqualTo(0)); // the ptr to the string in memory
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.STRING));
- vm.heap.Read(0, initialStr.Length * 4, out var memory);
+ vm.heap.Read(0.ToPtr(), initialStr.Length * 4, out var memory);
var str = VmConverter.ToString(memory);
Assert.That(str, Is.EqualTo(initialStr));
@@ -368,7 +368,7 @@ public void String_Declare_Anon()
Assert.That(vm.dataRegisters[0], Is.EqualTo(0)); // the ptr to the string in memory
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.STRING));
- vm.heap.Read(0, "hello".Length * 4, out var memory);
+ vm.heap.Read(0.ToPtr(), "hello".Length * 4, out var memory);
var str = VmConverter.ToString(memory);
Assert.That(str, Is.EqualTo("hello"));
@@ -384,16 +384,16 @@ public void String_Declare3()
Assert.That(vm.dataRegisters[0], Is.EqualTo(0)); // the ptr to the string in memory
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.STRING));
- Assert.That(vm.dataRegisters[1], Is.EqualTo("hello".Length*4)); // the ptr to the string in memory
+ Assert.That(vm.dataRegisters[1].ToPtr(), Is.EqualTo(("hello".Length*4).ToPtr())); // the ptr to the string in memory
Assert.That(vm.typeRegisters[1], Is.EqualTo(TypeCodes.STRING));
- vm.heap.Read(0, "hello".Length * 4, out var memory);
+ vm.heap.Read(0.ToPtr(), "hello".Length * 4, out var memory);
var str = VmConverter.ToString(memory);
Assert.That(str, Is.EqualTo("hello"));
- vm.heap.Read("hello".Length * 4, "world".Length * 4, out memory);
+ vm.heap.Read(("hello".Length * 4).ToPtr(), "world".Length * 4, out memory);
str = VmConverter.ToString(memory);
Assert.That(str, Is.EqualTo("world"));
@@ -1818,7 +1818,7 @@ y as byte
var vm = new VirtualMachine(prog);
vm.Execute2();
- Assert.That(vm.heap.Cursor, Is.EqualTo(4));
+ Assert.That(vm.heap.Cursor, Is.EqualTo(4.ToPtr()));
var heap = vm.heap;
Assert.That(vm.dataRegisters[0], Is.EqualTo(0));
@@ -1844,7 +1844,7 @@ y as byte
var vm = new VirtualMachine(prog);
vm.Execute2();
- Assert.That(vm.heap.Cursor, Is.EqualTo(4));
+ Assert.That(vm.heap.Cursor, Is.EqualTo(4.ToPtr()));
Assert.That(vm.dataRegisters[0], Is.EqualTo(0));
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.INT));
@@ -1894,7 +1894,7 @@ dim x(4)
var vm = new VirtualMachine(prog);
vm.Execute2();
- Assert.That(vm.heap.Cursor, Is.EqualTo(16));
+ Assert.That(vm.heap.Cursor, Is.EqualTo(16.ToPtr()));
Assert.That(vm.dataRegisters[0], Is.EqualTo(0));
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.INT));
@@ -1915,7 +1915,7 @@ public void Array_Math_Floats()
var vm = new VirtualMachine(prog);
vm.Execute2();
- Assert.That(vm.heap.Cursor, Is.EqualTo(16));
+ Assert.That(vm.heap.Cursor, Is.EqualTo(16.ToPtr()));
Assert.That(vm.dataRegisters[0], Is.EqualTo(0));
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.INT));
@@ -1947,7 +1947,7 @@ dim x(4)
Assert.That(vm.dataRegisters[0], Is.EqualTo(0));
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.INT));
- Assert.That(vm.heap.Cursor, Is.EqualTo(16));
+ Assert.That(vm.heap.Cursor, Is.EqualTo(16.ToPtr()));
}
@@ -1965,7 +1965,7 @@ dim x(4,2)
Assert.That(vm.dataRegisters[0], Is.EqualTo(0));
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.INT));
- Assert.That(vm.heap.Cursor, Is.EqualTo(32));
+ Assert.That(vm.heap.Cursor, Is.EqualTo(32.ToPtr()));
}
@@ -1984,10 +1984,10 @@ dim x(4,2) as word
Assert.That(vm.dataRegisters[0], Is.EqualTo(0));
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.INT));
- Assert.That(vm.heap.Cursor, Is.EqualTo(16));
+ Assert.That(vm.heap.Cursor, Is.EqualTo(16.ToPtr()));
- vm.heap.Read((1*2 + 1) * 2, 2, out var bytes);
+ vm.heap.Read(((1*2 + 1) * 2).ToPtr(), 2, out var bytes);
var value = BitConverter.ToInt16(bytes, 0);
Assert.That(value, Is.EqualTo(42));
}
@@ -2007,10 +2007,10 @@ dim x(4,5,3) as word
Assert.That(vm.dataRegisters[0], Is.EqualTo(0));
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.INT));
- Assert.That(vm.heap.Cursor, Is.EqualTo(120));
+ Assert.That(vm.heap.Cursor, Is.EqualTo(120.ToPtr()));
- vm.heap.Read(( (2*5*3) + (3*3) + 2) * 2, 2, out var bytes);
+ vm.heap.Read((( (2*5*3) + (3*3) + 2) * 2).ToPtr(), 2, out var bytes);
var value = BitConverter.ToInt16(bytes, 0);
Assert.That(value, Is.EqualTo(42));
}
@@ -2033,7 +2033,7 @@ y as word
Assert.That(vm.dataRegisters[0], Is.EqualTo(0));
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.INT));
- Assert.That(vm.heap.Cursor, Is.EqualTo(120));
+ Assert.That(vm.heap.Cursor, Is.EqualTo(120.ToPtr()));
Assert.That(vm.dataRegisters[1 + (3*2) /* 3 ranks, 2 registers per rank. */], Is.EqualTo(42));
Assert.That(vm.typeRegisters[1 + (3*2)], Is.EqualTo(TypeCodes.WORD));
@@ -2057,7 +2057,7 @@ dim x(4,5,3) as byte
Assert.That(vm.dataRegisters[0], Is.EqualTo(0));
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.INT));
- Assert.That(vm.heap.Cursor, Is.EqualTo(60));
+ Assert.That(vm.heap.Cursor, Is.EqualTo(60.ToPtr()));
Assert.That(vm.dataRegisters[1 + (3*2) /* 3 ranks, 2 registers per rank. */], Is.EqualTo(53));
Assert.That(vm.typeRegisters[1 + (3*2)], Is.EqualTo(TypeCodes.INT));
@@ -2078,7 +2078,7 @@ dim x(4) as word
Assert.That(vm.dataRegisters[0], Is.EqualTo(0));
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.INT));
- Assert.That(vm.heap.Cursor, Is.EqualTo(8));
+ Assert.That(vm.heap.Cursor, Is.EqualTo(8.ToPtr()));
}
@@ -2123,9 +2123,9 @@ dim x(5) as word
Assert.That(vm.dataRegisters[0], Is.EqualTo(0));
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.INT));
- Assert.That(vm.heap.Cursor, Is.EqualTo(10));
+ Assert.That(vm.heap.Cursor, Is.EqualTo(10.ToPtr()));
- vm.heap.Read(2, 2, out var bytes);
+ vm.heap.Read(2.ToPtr(), 2, out var bytes);
var value = BitConverter.ToInt16(bytes, 0);
Assert.That(value, Is.EqualTo(12));
}
@@ -2147,13 +2147,13 @@ dim x(5) as word
Assert.That(vm.dataRegisters[0], Is.EqualTo(0));
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.INT));
- Assert.That(vm.heap.Cursor, Is.EqualTo(10));
+ Assert.That(vm.heap.Cursor, Is.EqualTo(10.ToPtr()));
- vm.heap.Read(2, 2, out var bytes);
+ vm.heap.Read(2.ToPtr(), 2, out var bytes);
var value = BitConverter.ToInt16(bytes, 0);
Assert.That(value, Is.EqualTo(12));
- vm.heap.Read(4, 2, out bytes);
+ vm.heap.Read(4.ToPtr(), 2, out bytes);
value = BitConverter.ToInt16(bytes, 0);
Assert.That(value, Is.EqualTo(5));
}
@@ -2175,13 +2175,13 @@ dim x(5) as word
Assert.That(vm.dataRegisters[0], Is.EqualTo(0));
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.INT));
- Assert.That(vm.heap.Cursor, Is.EqualTo(10));
+ Assert.That(vm.heap.Cursor, Is.EqualTo(10.ToPtr()));
- vm.heap.Read(2, 2, out var bytes);
+ vm.heap.Read(2.ToPtr(), 2, out var bytes);
var value = BitConverter.ToInt16(bytes, 0);
Assert.That(value, Is.EqualTo(12));
- vm.heap.Read(4, 2, out bytes);
+ vm.heap.Read(4.ToPtr(), 2, out bytes);
value = BitConverter.ToInt16(bytes, 0);
Assert.That(value, Is.EqualTo(24));
}
@@ -2573,8 +2573,8 @@ global x
Assert.That(vm.globalScope.dataRegisters[1], Is.EqualTo(4)); // register 1 is y,
Assert.That(vm.globalScope.typeRegisters[1], Is.EqualTo(TypeCodes.INT));
- Assert.That(vm.dataRegisters[2], Is.EqualTo(0)); // register 2 should have nothing in it
- Assert.That(vm.typeRegisters[2], Is.EqualTo(0));
+ Assert.That(vm.dataRegisters.Length, Is.EqualTo(3)); // 2, plus 1 for the debugger room
+ Assert.That(vm.typeRegisters.Length, Is.EqualTo(3));
}
@@ -2597,9 +2597,9 @@ public void Declare_InLoop()
Assert.That(vm.globalScope.dataRegisters[1], Is.EqualTo(3)); // register 1 is y,
Assert.That(vm.globalScope.typeRegisters[1], Is.EqualTo(TypeCodes.INT));
-
- Assert.That(vm.dataRegisters[2], Is.EqualTo(0)); // register 2 should have nothing in it
- Assert.That(vm.typeRegisters[2], Is.EqualTo(0));
+
+ Assert.That(vm.dataRegisters.Length, Is.EqualTo(3)); // 2, plus 1 for the debugger room
+ Assert.That(vm.typeRegisters.Length, Is.EqualTo(3));
}
@@ -2816,7 +2816,7 @@ public void Math_NegativeSignFlip()
Assert.That(vm.dataRegisters[1], Is.EqualTo(0)); // the ptr to the string in memory
Assert.That(vm.typeRegisters[1], Is.EqualTo(TypeCodes.STRING));
- vm.heap.Read(0, "-4".Length * 4, out var memory);
+ vm.heap.Read(0.ToPtr(), "-4".Length * 4, out var memory);
var str = VmConverter.ToString(memory);
Assert.That(str, Is.EqualTo("-4"));
}
@@ -2931,7 +2931,7 @@ a as egg
vm.hostMethods = compiler.methodTable;
vm.Execute2();
- Assert.That(vm.heap.Cursor, Is.EqualTo(8)); // size of the only field in egg, int, 4. (times 2, because there are 2 copies)
+ Assert.That(vm.heap.Cursor, Is.EqualTo(8.ToPtr())); // size of the only field in egg, int, 4. (times 2, because there are 2 copies)
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.STRUCT));
Assert.That(vm.typeRegisters[1], Is.EqualTo(TypeCodes.STRUCT));
}
@@ -2953,7 +2953,7 @@ y as egg
vm.hostMethods = compiler.methodTable;
vm.Execute2();
- Assert.That(vm.heap.Cursor, Is.EqualTo(4)); // size of the only field in egg, int, 4.
+ Assert.That(vm.heap.Cursor, Is.EqualTo(4.ToPtr())); // size of the only field in egg, int, 4.
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.STRUCT));
}
@@ -2974,10 +2974,10 @@ y as egg
vm.hostMethods = compiler.methodTable;
vm.Execute2();
- Assert.That(vm.heap.Cursor, Is.EqualTo(4)); // size of the only field in egg, int, 4.
+ Assert.That(vm.heap.Cursor, Is.EqualTo(4.ToPtr())); // size of the only field in egg, int, 4.
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.STRUCT));
- vm.heap.Read((int)vm.dataRegisters[0], 4, out var memory);
+ vm.heap.Read(vm.dataRegisters[0].ToPtr(), 4, out var memory);
var data = BitConverter.ToInt32(memory);
Assert.That(data, Is.EqualTo(53));
}
@@ -3000,10 +3000,10 @@ y as egg
vm.hostMethods = compiler.methodTable;
vm.Execute2();
- Assert.That(vm.heap.Cursor, Is.EqualTo(4)); // size of the only field in egg, int, 4.
+ Assert.That(vm.heap.Cursor, Is.EqualTo(4.ToPtr())); // size of the only field in egg, int, 4.
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.STRUCT));
- vm.heap.Read((int)vm.dataRegisters[0], 4, out var memory);
+ vm.heap.Read(vm.dataRegisters[0].ToPtr(), 4, out var memory);
var data = BitConverter.ToInt32(memory);
Assert.That(data, Is.EqualTo(106));
}
@@ -3028,7 +3028,7 @@ y as egg
vm.hostMethods = compiler.methodTable;
vm.Execute2();
- Assert.That(vm.heap.Cursor, Is.EqualTo(8));
+ Assert.That(vm.heap.Cursor, Is.EqualTo(8.ToPtr()));
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.STRUCT));
Assert.That(vm.typeRegisters[1], Is.EqualTo(TypeCodes.INT));
@@ -3055,7 +3055,7 @@ y as egg
vm.Execute2();
- Assert.That(vm.heap.Cursor, Is.EqualTo(4 + 4 + "hello".Length*4)); // a '4' comes from y.x, and the other '4' is the ptr to z$
+ Assert.That(vm.heap.Cursor, Is.EqualTo(12.ToPtr() + ("hello".Length*4))); // egg is 4+8 big (an int plus a pointer), and the size of the string.
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.STRUCT));
Assert.That(vm.typeRegisters[1], Is.EqualTo(TypeCodes.INT));
@@ -3084,7 +3084,7 @@ albert as chicken
vm.Execute2();
- Assert.That(vm.heap.Cursor, Is.EqualTo(8));
+ Assert.That(vm.heap.Cursor, Is.EqualTo(8.ToPtr()));
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.STRUCT));
// Assert.That(vm.typeRegisters[1], Is.EqualTo(TypeCodes.INT));
@@ -3113,7 +3113,7 @@ albert as chicken
vm.Execute2();
- Assert.That(vm.heap.Cursor, Is.EqualTo(8));
+ Assert.That(vm.heap.Cursor, Is.EqualTo(8.ToPtr()));
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.STRUCT));
// it shouldn't matter the order we define the types, because we are parse-sure they don't have loops.
@@ -3148,7 +3148,7 @@ player as object
vm.Execute2();
- Assert.That(vm.heap.Cursor, Is.EqualTo(16));
+ Assert.That(vm.heap.Cursor, Is.EqualTo(16.ToPtr()));
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.STRUCT));
Assert.That(vm.typeRegisters[1], Is.EqualTo(TypeCodes.INT));
@@ -3186,7 +3186,7 @@ player as object
vm.Execute2();
- Assert.That(vm.heap.Cursor, Is.EqualTo(16));
+ Assert.That(vm.heap.Cursor, Is.EqualTo(16.ToPtr()));
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.STRUCT));
Assert.That(vm.typeRegisters[1], Is.EqualTo(TypeCodes.INT));
@@ -3218,7 +3218,7 @@ albert AS chicken
vm.Execute2();
- Assert.That(vm.heap.Cursor, Is.EqualTo(8));
+ Assert.That(vm.heap.Cursor, Is.EqualTo(8.ToPtr()));
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.STRUCT));
Assert.That(vm.typeRegisters[1], Is.EqualTo(TypeCodes.INT));
@@ -3242,7 +3242,7 @@ DIM x(3) AS egg
vm.Execute2();
- Assert.That(vm.heap.Cursor, Is.EqualTo(12));
+ Assert.That(vm.heap.Cursor, Is.EqualTo(12.ToPtr()));
// Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.STRUCT));
}
@@ -3264,7 +3264,7 @@ DIM x(3) AS egg
vm.Execute2();
- Assert.That(vm.heap.Cursor, Is.EqualTo(6));
+ Assert.That(vm.heap.Cursor, Is.EqualTo(6.ToPtr()));
// Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.STRUCT));
}
@@ -3286,9 +3286,9 @@ DIM x(3) AS egg
vm.Execute2();
- Assert.That(vm.heap.Cursor, Is.EqualTo(6));
+ Assert.That(vm.heap.Cursor, Is.EqualTo(6.ToPtr()));
- vm.heap.Read(1 * 2, 2, out var mem);
+ vm.heap.Read((1 * 2).ToPtr(), 2, out var mem);
var data = BitConverter.ToInt16(mem, 0);
Assert.That(data, Is.EqualTo(3));
@@ -3313,9 +3313,9 @@ DIM x(3,2) AS egg
vm.Execute2();
- Assert.That(vm.heap.Cursor, Is.EqualTo(12));
+ Assert.That(vm.heap.Cursor, Is.EqualTo(12.ToPtr()));
- vm.heap.Read((1 + 2 * 1) * 2, 2, out var mem);
+ vm.heap.Read(((1 + 2 * 1) * 2).ToPtr(), 2, out var mem);
var data = BitConverter.ToInt16(mem, 0);
Assert.That(data, Is.EqualTo(3));
@@ -3342,7 +3342,7 @@ DIM x(3) AS egg
vm.Execute2();
- Assert.That(vm.heap.Cursor, Is.EqualTo(18));
+ Assert.That(vm.heap.Cursor, Is.EqualTo(18.ToPtr()));
Assert.That(vm.dataRegisters[3], Is.EqualTo(3));
@@ -3367,7 +3367,7 @@ DIM x(3,4) AS egg
vm.hostMethods = compiler.methodTable;
vm.Execute2();
- Assert.That(vm.heap.Cursor, Is.EqualTo(6*12));
+ Assert.That(vm.heap.Cursor, Is.EqualTo((6*12).ToPtr()));
Assert.That(vm.globalScope.dataRegisters[3], Is.EqualTo(3));
}
@@ -3401,7 +3401,7 @@ n as egg
vm.hostMethods = compiler.methodTable;
vm.Execute2();
- Assert.That(vm.heap.Cursor, Is.EqualTo(6*(3 + 1))); // 1 extra for the original assignment of n as egg
+ Assert.That(vm.heap.Cursor, Is.EqualTo((6*(3 + 1)).ToPtr())); // 1 extra for the original assignment of n as egg
Assert.That(vm.dataRegisters[0], Is.EqualTo(122));
}
@@ -3426,7 +3426,7 @@ DIM x(3) AS egg
vm.Execute2();
- Assert.That(vm.heap.Cursor, Is.EqualTo(18));
+ Assert.That(vm.heap.Cursor, Is.EqualTo(18.ToPtr()));
Assert.That(vm.dataRegisters[3], Is.EqualTo(6));
@@ -3534,10 +3534,10 @@ dim bread(2) as toast
var vm = new VirtualMachine(prog);
vm.hostMethods = compiler.methodTable;
vm.Execute2();
- Assert.That(vm.heap.Cursor, Is.EqualTo(8)); // size of the only field in toast, int, 4.
+ Assert.That(vm.heap.Cursor, Is.EqualTo(8.ToPtr())); // size of the only field in toast, int, 4.
// Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.PTR_HEAP));
- vm.heap.Read((int)vm.dataRegisters[0] + 4, 4, out var memory);
+ vm.heap.Read(vm.dataRegisters[0].ToPtr() + 4, 4, out var memory);
var data = BitConverter.ToInt32(memory);
Assert.That(data, Is.EqualTo(6));
}
@@ -3557,10 +3557,10 @@ bread as toast
var vm = new VirtualMachine(prog);
vm.hostMethods = compiler.methodTable;
vm.Execute2();
- Assert.That(vm.heap.Cursor, Is.EqualTo(4)); // size of the only field in toast, int, 4.
+ Assert.That(vm.heap.Cursor, Is.EqualTo(4.ToPtr())); // size of the only field in toast, int, 4.
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.STRUCT));
- vm.heap.Read((int)vm.dataRegisters[0], 4, out var memory);
+ vm.heap.Read(vm.dataRegisters[0].ToPtr(), 4, out var memory);
var data = BitConverter.ToInt32(memory);
Assert.That(data, Is.EqualTo(6));
}
@@ -3582,10 +3582,10 @@ dim bread(2) as toast
var vm = new VirtualMachine(prog);
vm.hostMethods = compiler.methodTable;
vm.Execute2();
- Assert.That(vm.heap.Cursor, Is.EqualTo(16)); // size of the only field in toast, int, 4.
+ Assert.That(vm.heap.Cursor, Is.EqualTo(16.ToPtr())); // size of the only field in toast, int, 4.
// Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.PTR_HEAP));
- vm.heap.Read((int)vm.dataRegisters[0] + 12, 4, out var memory);
+ vm.heap.Read(vm.dataRegisters[0].ToPtr() + 12, 4, out var memory);
var data = BitConverter.ToInt32(memory);
Assert.That(data, Is.EqualTo(6));
}
@@ -3611,10 +3611,10 @@ dim bread(2) as toast
var vm = new VirtualMachine(prog);
vm.hostMethods = compiler.methodTable;
vm.Execute2();
- Assert.That(vm.heap.Cursor, Is.EqualTo(24)); // size of the only field in toast, int, 4.
+ Assert.That(vm.heap.Cursor, Is.EqualTo(24.ToPtr())); // size of the only field in toast, int, 4.
// Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.PTR_HEAP));
- vm.heap.Read((int)vm.dataRegisters[0] + 20, 4, out var memory);
+ vm.heap.Read(vm.dataRegisters[0].ToPtr() + 20, 4, out var memory);
var data = BitConverter.ToInt32(memory);
Assert.That(data, Is.EqualTo(6));
}
@@ -3636,10 +3636,10 @@ bread as toast
var vm = new VirtualMachine(prog);
vm.hostMethods = compiler.methodTable;
vm.Execute2();
- Assert.That(vm.heap.Cursor, Is.EqualTo(8)); // there are two ints, each are 4
+ Assert.That(vm.heap.Cursor, Is.EqualTo(8.ToPtr())); // there are two ints, each are 4
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.STRUCT));
- vm.heap.Read((int)vm.dataRegisters[0] + 4, 4, out var memory);
+ vm.heap.Read(vm.dataRegisters[0].ToPtr() + 4, 4, out var memory);
var data = BitConverter.ToInt32(memory);
Assert.That(data, Is.EqualTo(6));
}
@@ -3667,10 +3667,10 @@ bread as toast
var vm = new VirtualMachine(prog);
vm.hostMethods = compiler.methodTable;
vm.Execute2();
- Assert.That(vm.heap.Cursor, Is.EqualTo(12)); // there are three ints, each are 4
+ Assert.That(vm.heap.Cursor, Is.EqualTo(12.ToPtr())); // there are three ints, each are 4
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.STRUCT));
- vm.heap.Read((int)vm.dataRegisters[0] + 8, 4, out var memory);
+ vm.heap.Read(vm.dataRegisters[0].ToPtr() + 8, 4, out var memory);
var data = BitConverter.ToInt32(memory);
Assert.That(data, Is.EqualTo(6));
}
@@ -3864,7 +3864,7 @@ public void CallHost_Params_Object()
vm.hostMethods = compiler.methodTable;
vm.Execute2();
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.STRING));
- vm.heap.Read((int)vm.dataRegisters[0], "1;hello;2".Length * 4, out var memory);
+ vm.heap.Read(vm.dataRegisters[0].ToPtr(), "1;hello;2".Length * 4, out var memory);
var str = VmConverter.ToString(memory);
Assert.That(str, Is.EqualTo("1;hello;2"));
}
@@ -3879,7 +3879,7 @@ public void CallHost_RefType_String()
vm.hostMethods = compiler.methodTable;
vm.Execute2();
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.STRING));
- vm.heap.Read((int)vm.dataRegisters[0], "tuna".Length * 4, out var memory);
+ vm.heap.Read(vm.dataRegisters[0].ToPtr(), "tuna".Length * 4, out var memory);
var str = VmConverter.ToString(memory);
Assert.That(str, Is.EqualTo("tuna"));
}
@@ -3893,7 +3893,7 @@ public void CallHost_RefType_String_2()
vm.hostMethods = compiler.methodTable;
vm.Execute2();
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.STRING));
- vm.heap.Read((int)vm.dataRegisters[0], "tuna".Length * 4, out var memory);
+ vm.heap.Read(vm.dataRegisters[0].ToPtr(), "tuna".Length * 4, out var memory);
var str = VmConverter.ToString(memory);
Assert.That(str, Is.EqualTo("tuna"));
}
@@ -3968,12 +3968,31 @@ public void CallHost_RefType_String_FromArray()
vm.hostMethods = compiler.methodTable;
vm.Execute2();
Assert.That(vm.typeRegisters[3], Is.EqualTo(TypeCodes.STRING));
- vm.heap.Read((int)vm.dataRegisters[3], "tuna".Length * 4, out var memory);
+ vm.heap.Read(vm.dataRegisters[3].ToPtr(), "tuna".Length * 4, out var memory);
var str = VmConverter.ToString(memory);
Assert.That(str, Is.EqualTo("tuna"));
}
+ [Test]
+ public void Array_StringAssign()
+ {
+ var src = @"
+dim x$(3)
+x$(1) = ""tuna""
+y$ = x$(1)
+";
+
+ Setup(src, out var compiler, out var prog);
+ var vm = new VirtualMachine(prog);
+ vm.hostMethods = compiler.methodTable;
+ vm.Execute2();
+ Assert.That(vm.typeRegisters[3], Is.EqualTo(TypeCodes.STRING));
+ vm.heap.Read(vm.dataRegisters[3].ToPtr(), "tuna".Length * 4, out var memory);
+ var str = VmConverter.ToString(memory);
+ Assert.That(str, Is.EqualTo("tuna"));
+ }
+
[Test]
public void CallHost_StringArg()
{
@@ -4028,12 +4047,12 @@ public void CallHost_StringArg_FromArray()
Assert.That(vm.typeRegisters[3], Is.EqualTo(TypeCodes.INT));
Assert.That(vm.dataRegisters[3], Is.EqualTo("hello".Length));
Assert.That(vm.typeRegisters[4], Is.EqualTo(TypeCodes.STRING));
- vm.heap.Read((int)vm.dataRegisters[4], "hello".Length * 4, out var memory);
+ vm.heap.Read(vm.dataRegisters[4].ToPtr(), "hello".Length * 4, out var memory);
var str = VmConverter.ToString(memory);
Assert.That(str, Is.EqualTo("olleh"));
Assert.That(vm.typeRegisters[5], Is.EqualTo(TypeCodes.STRING));
- vm.heap.Read((int)vm.dataRegisters[5], "hello".Length * 4, out memory);
+ vm.heap.Read(vm.dataRegisters[5].ToPtr(), "hello".Length * 4, out memory);
str = VmConverter.ToString(memory);
Assert.That(str, Is.EqualTo("olleh"));
}
@@ -4048,7 +4067,7 @@ public void CallHost_StringReturn()
vm.hostMethods = compiler.methodTable;
vm.Execute2();
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.STRING));
- vm.heap.Read((int)vm.dataRegisters[0], "hello".Length * 4, out var memory);
+ vm.heap.Read(vm.dataRegisters[0].ToPtr(), "hello".Length * 4, out var memory);
var str = VmConverter.ToString(memory);
Assert.That(str, Is.EqualTo("olleh"));
}
@@ -4063,7 +4082,7 @@ public void CallHost_StringReturn_2()
vm.hostMethods = compiler.methodTable;
vm.Execute2();
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.STRING));
- vm.heap.Read((int)vm.dataRegisters[0], "32".Length * 4, out var memory);
+ vm.heap.Read(vm.dataRegisters[0].ToPtr(), "32".Length * 4, out var memory);
var str = VmConverter.ToString(memory);
Assert.That(str, Is.EqualTo("32"));
}
@@ -4077,12 +4096,12 @@ public void CallHost_StringReturn_Assignment()
vm.hostMethods = compiler.methodTable;
vm.Execute2();
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.STRING));
- vm.heap.Read((int)vm.dataRegisters[0], "hello".Length * 4, out var memory);
+ vm.heap.Read(vm.dataRegisters[0].ToPtr(), "hello".Length * 4, out var memory);
var str = VmConverter.ToString(memory);
Assert.That(str, Is.EqualTo("hello"));
Assert.That(vm.typeRegisters[1], Is.EqualTo(TypeCodes.STRING));
- vm.heap.Read((int)vm.dataRegisters[1], "hello".Length * 4, out memory);
+ vm.heap.Read(vm.dataRegisters[1].ToPtr(), "hello".Length * 4, out memory);
str = VmConverter.ToString(memory);
Assert.That(str, Is.EqualTo("olleh"));
}
@@ -4097,12 +4116,12 @@ public void CallHost_StringReturn_Expression()
vm.hostMethods = compiler.methodTable;
vm.Execute2();
Assert.That(vm.typeRegisters[0], Is.EqualTo(TypeCodes.STRING));
- vm.heap.Read((int)vm.dataRegisters[0], "hello".Length * 4, out var memory);
+ vm.heap.Read(vm.dataRegisters[0].ToPtr(), "hello".Length * 4, out var memory);
var str = VmConverter.ToString(memory);
Assert.That(str, Is.EqualTo("hello"));
Assert.That(vm.typeRegisters[1], Is.EqualTo(TypeCodes.STRING));
- vm.heap.Read((int)vm.dataRegisters[1], "helloworld".Length * 4, out memory);
+ vm.heap.Read(vm.dataRegisters[1].ToPtr(), "helloworld".Length * 4, out memory);
str = VmConverter.ToString(memory);
Assert.That(str, Is.EqualTo("worldolleh"));
}
diff --git a/FadeBasic/Tests/TokenVm_BigSrc.cs b/FadeBasic/Tests/TokenVm_BigSrc.cs
new file mode 100644
index 0000000..28565ed
--- /dev/null
+++ b/FadeBasic/Tests/TokenVm_BigSrc.cs
@@ -0,0 +1,67 @@
+using System.Text;
+using FadeBasic.Virtual;
+
+namespace Tests;
+
+public partial class TokenVm
+{
+
+ [Test]
+ public void BigSrc_GiantHeap()
+ {
+ var src = @"
+TYPE egg
+ x#, y#
+ENDTYPE
+e as egg
+e.x# = 1.2
+e.y# = 3.4
+
+";
+ Setup(src, out var compiler, out var prog);
+ var vm = new VirtualMachine(prog);
+ vm.hostMethods = compiler.methodTable;
+
+ // allocation a bunch of memory
+ vm.heap.Allocate(ref HeapTypeFormat.STRING_FORMAT, (int)VmPtr.MAX_ARRAY_SIZE - 1, out var dumbPtr);
+
+ vm.Execute2(0);
+
+ var expectedPtr = new VmPtr
+ {
+ bucketPtr = 1,
+ memoryPtr = 0
+ };
+ if (!vm.heap.TryGetAllocation(expectedPtr, out var allocation))
+ {
+ Assert.Fail("pointer is not at expected location");
+ }
+
+ Assert.That(allocation.length, Is.EqualTo(8)); // 2 floats
+ }
+
+
+ [Test]
+ public void BigSrc_LotsOfVariables()
+ {
+ var sb = new StringBuilder();
+ var max = short.MaxValue / 2; // this number cannot get to big, because the string-builder explodes.
+ for (int i = 0; i < max; i++)
+ {
+ sb.AppendLine($"x_{i} = {i}");
+ }
+
+ var src = sb.ToString();
+ Setup(src, out var compiler, out var prog);
+ var vm = new VirtualMachine(prog);
+ vm.hostMethods = compiler.methodTable;
+ vm.Execute2(0);
+
+ for (int i = 0; i < max; i++)
+ {
+ Assert.That(vm.dataRegisters[i], Is.EqualTo(i), $"variable at reg {i} is wrong.");
+
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/FadeBasic/Tests/TokenVm_GC.cs b/FadeBasic/Tests/TokenVm_GC.cs
index 52ca15e..b5c0ba6 100644
--- a/FadeBasic/Tests/TokenVm_GC.cs
+++ b/FadeBasic/Tests/TokenVm_GC.cs
@@ -113,7 +113,7 @@ public void String_Interning(string str, string expected)
Assert.That(xPtr, Is.EqualTo(0));
Assert.That(yPtr, Is.EqualTo(xPtr));
- vm.heap.Read((int)xPtr, expected.Length * 4, out var memory);
+ vm.heap.Read(xPtr.ToPtr(), expected.Length * 4, out var memory);
var actual = VmConverter.ToString(memory);
Assert.That(actual, Is.EqualTo(expected));