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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 35 additions & 10 deletions src/Engine/ProtoCore/AssociativeGraph.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,17 @@ public class Utils
public static AssociativeGraph.GraphNode GetGraphNodeAtPC(int pc, List<AssociativeGraph.GraphNode> graphNodesInScope)
{
Validity.Assert(graphNodesInScope != null);
return graphNodesInScope.FirstOrDefault(g => g.isActive && g.isDirty && g.updateBlock.startpc == pc);

for (int i = 0; i < graphNodesInScope.Count; i++)
{
var g = graphNodesInScope[i];
if (g.isActive && g.isDirty && g.updateBlock.startpc == pc)
{
return g;
}
}

return null;
}

/// <summary>
Expand All @@ -29,7 +39,17 @@ public static AssociativeGraph.GraphNode GetGraphNodeAtPC(int pc, List<Associati
public static AssociativeGraph.GraphNode GetFirstDirtyGraphNodeFromPC(int pc, List<AssociativeGraph.GraphNode> graphNodesInScope)
{
Validity.Assert(graphNodesInScope != null);
return graphNodesInScope.FirstOrDefault(g => g.isActive && g.isDirty && g.updateBlock.startpc >= pc);

for (int i = 0; i < graphNodesInScope.Count; i++)
{
var g = graphNodesInScope[i];
if (g.isActive && g.isDirty && g.updateBlock.startpc >= pc)
{
return g;
}
}

return null;
}

/// <summary>
Expand Down Expand Up @@ -659,23 +679,28 @@ public static bool IsGraphNodeRedefined(AssociativeGraph.GraphNode gnode, Associ
List<AssociativeGraph.GraphNode> redefinedNodes = new List<AssociativeGraph.GraphNode>();
if (executingGraphNode != null)
{
// Remove this condition when full SSA is enabled
bool isssa = (!executingGraphNode.IsSSANode() && executingGraphNode.DependsOnTempSSA());

bool isssa;
if (runtimeCore.Options.ExecuteSSA)
{
isssa = executingGraphNode.IsSSANode();
}
else
{
// Remove this condition when full SSA is enabled
isssa = (!executingGraphNode.IsSSANode() && executingGraphNode.DependsOnTempSSA());
}

if (!isssa)
{

SymbolNode symbol = executingGraphNode.updateNodeRefList[0].nodeList[0].symbol;
bool isMember = symbol.classScope != Constants.kInvalidIndex
&& symbol.functionIndex == Constants.kInvalidIndex;

foreach (AssociativeGraph.GraphNode graphNode in nodesInScope)
{
bool allowRedefine = true;

SymbolNode symbol = executingGraphNode.updateNodeRefList[0].nodeList[0].symbol;
bool isMember = symbol.classScope != Constants.kInvalidIndex
&& symbol.functionIndex == Constants.kInvalidIndex;

if (isMember)
{
// For member vars, do not allow if not in the same scope
Expand Down Expand Up @@ -1475,7 +1500,7 @@ public bool IsSSANode()
return false;
}

var firstNode = updateNodeRefList.First().nodeList.FirstOrDefault();
var firstNode = updateNodeRefList[0].nodeList[0];
return firstNode != null && firstNode.nodeType == UpdateNodeType.Symbol && firstNode.symbol.isSSATemp;
Comment on lines +1503 to 1504
Copy link
Preview

Copilot AI Jun 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accessing updateNodeRefList[0].nodeList[0] without checking for an empty list can throw IndexOutOfRangeException. Validate both lists before indexing or revert to a safe lookup.

Suggested change
var firstNode = updateNodeRefList[0].nodeList[0];
return firstNode != null && firstNode.nodeType == UpdateNodeType.Symbol && firstNode.symbol.isSSATemp;
if (updateNodeRefList.Count > 0 && updateNodeRefList[0].nodeList.Count > 0)
{
var firstNode = updateNodeRefList[0].nodeList[0];
return firstNode != null && firstNode.nodeType == UpdateNodeType.Symbol && firstNode.symbol.isSSATemp;
}
return false;

Copilot uses AI. Check for mistakes.

}
}
Expand Down
8 changes: 7 additions & 1 deletion src/Engine/ProtoCore/DSASM/DSObject.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using ProtoCore.Properties;
using ProtoCore.Runtime;

Expand All @@ -12,6 +12,12 @@ public DSObject(int size, Heap heap)
MetaData = new MetaData { type = (int)PrimitiveType.Pointer };
}

public DSObject(int size, Heap heap, MetaData metaData)
: base(size, heap)
{
MetaData = metaData;
}

public DSObject(StackValue[] values, Heap heap)
: base(values, heap)
{
Expand Down
52 changes: 43 additions & 9 deletions src/Engine/ProtoCore/DSASM/Executive.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,17 @@ public Executive(RuntimeCore runtimeCore, bool isFep = false)
deferedGraphNodes = new List<AssociativeGraph.GraphNode>();
}

public void Reset(bool isFep = false)
{
pc = Constants.kInvalidIndex;
executingBlock = Constants.kInvalidIndex;
RX = StackValue.BuildInvalid();
TX = StackValue.BuildInvalid();
fepRun = isFep;
terminate = false;
graphNodesInProgramScope = null;
}

/// <summary>
/// Cache the graphnodes in scope
/// </summary>
Expand Down Expand Up @@ -2308,15 +2319,35 @@ private void Execute(int exeblock, int entry, Language language = Language.NotSp
}
}

private int cacheBlockID = -1;
private int cacheClassIndex = -1;
private int cachesymbolIndex = -1;
private SymbolNode cachedSymbol = null;

protected SymbolNode GetSymbolNode(int blockId, int classIndex, int symbolIndex)
{
if (blockId == cacheBlockID && classIndex == cacheClassIndex && symbolIndex == cachesymbolIndex && cachedSymbol != null)
{
return cachedSymbol;
}

if (Constants.kGlobalScope == classIndex)
{
return exe.runtimeSymbols[blockId].symbolList[symbolIndex];
var symbol = exe.runtimeSymbols[blockId].symbolList[symbolIndex];
cacheBlockID = blockId;
cacheClassIndex = classIndex;
cachesymbolIndex = symbolIndex;
cachedSymbol = symbol;
return symbol;
}
else
{
return exe.classTable.ClassNodes[classIndex].Symbols.symbolList[symbolIndex];
var symbol = exe.classTable.ClassNodes[classIndex].Symbols.symbolList[symbolIndex];
cacheBlockID = blockId;
cacheClassIndex = classIndex;
cachesymbolIndex = symbolIndex;
cachedSymbol = symbol;
return symbol;
}
}

Expand Down Expand Up @@ -2438,10 +2469,11 @@ protected StackValue PopTo(int blockId, StackValue op1, StackValue op2, StackVal
case AddressType.MemVarIndex:

SymbolNode symbol = GetSymbolNode(blockId, op2.ClassIndex, op1.SymbolIndex);
opPrev = rmem.GetSymbolValue(symbol);
rmem.SetSymbolValue(symbol, opVal);
exe.UpdatedSymbols.Add(symbol);
opPrev = rmem.SetSymbolValueAndGetPreviousValue(symbol, opVal);


exe.UpdatedSymbols.Add(symbol);
#if DEBUG
if (IsDebugRun())
{
logWatchWindow(blockId, op1.SymbolIndex);
Expand All @@ -2452,23 +2484,25 @@ protected StackValue PopTo(int blockId, StackValue op1, StackValue op2, StackVal
{
logWatchWindow(blockId, op1.SymbolIndex);
}

#endif
RecordExecutedGraphNode();
break;

case AddressType.StaticMemVarIndex:
var staticMember = GetSymbolNode(blockId, Constants.kGlobalScope, op1.StaticVariableIndex);
opPrev = rmem.GetSymbolValue(staticMember);
rmem.SetSymbolValue(staticMember, opVal);
exe.UpdatedSymbols.Add(staticMember);
opPrev = rmem.SetSymbolValueAndGetPreviousValue(staticMember, opVal);


exe.UpdatedSymbols.Add(staticMember);
#if DEBUG
if (IsDebugRun())
{
logWatchWindow(blockId, op1.StaticVariableIndex);
System.Console.ReadLine();
}

logWatchWindow(blockId, op1.StaticVariableIndex);
#endif
break;
case AddressType.Register:
{
Expand Down
13 changes: 8 additions & 5 deletions src/Engine/ProtoCore/DSASM/Heap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -297,8 +297,8 @@ public enum GCMark
Black // Objects that are in use (are not candidates for garbage collection) and have had all their references traced.
}

private readonly List<int> freeList = new List<int>();
private readonly List<HeapElement> heapElements = new List<HeapElement>();
private readonly List<int> freeList = new List<int>(GC_THRESHOLD);
private readonly List<HeapElement> heapElements = new List<HeapElement>(GC_THRESHOLD);
private HashSet<int> fixedHeapElements = new HashSet<int>();
private readonly StringTable stringTable = new StringTable();
// The expected lifetime of the sweepSet is start of GC to end of GC
Expand Down Expand Up @@ -402,9 +402,7 @@ public StackValue AllocatePointer(int size, MetaData metadata)
{
try
{
int index = AllocateInternal(size, PrimitiveType.Pointer);
var hpe = heapElements[index];
hpe.MetaData = metadata;
int index = AllocatePointerInternal(size, metadata);
return StackValue.BuildPointer(index, metadata);
}
catch (OutOfMemoryException)
Expand Down Expand Up @@ -583,6 +581,11 @@ private int AllocateInternal(int size, PrimitiveType type)
return AddHeapElement(hpe);
}

private int AllocatePointerInternal(int size, MetaData metaData)
{
return AddHeapElement(new DSObject(size, this, metaData));
}

private int AllocateInternal(StackValue[] values, PrimitiveType type)
{
HeapElement hpe = null;
Expand Down
26 changes: 19 additions & 7 deletions src/Engine/ProtoCore/FFI/CLRFFIFunctionPointer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -500,9 +500,24 @@ private string ErrorString(System.Exception ex)
return string.Format(Resources.OperationFailType2, ReflectionInfo.DeclaringType.Name, ReflectionInfo.Name, msg);
}

private object[] parameters = null;
private FFIParameterInfo[] paraminfos;
private List<StackValue> referencedParameters;
private object missing = Type.Missing;

public override object Execute(ProtoCore.Runtime.Context c, Interpreter dsi, List<StackValue> s)
{
var parameters = new List<object>();
if (parameters == null)
{
parameters = new object[mArgTypes.Length];
paraminfos = ReflectionInfo.GetParameters();
referencedParameters = new List<StackValue>();
}
else
{
referencedParameters.Clear();
}

if (s == null)
s = dsi.runtime.rmem.Stack;

Expand All @@ -525,9 +540,6 @@ public override object Execute(ProtoCore.Runtime.Context c, Interpreter dsi, Lis
return null; //Can't call a method on null object.
}

FFIParameterInfo[] paraminfos = ReflectionInfo.GetParameters();
List<StackValue> referencedParameters = new List<StackValue>();

for (int i = 0; i < mArgTypes.Length; ++i)
{
var opArg = s[i];
Expand All @@ -536,7 +548,7 @@ public override object Execute(ProtoCore.Runtime.Context c, Interpreter dsi, Lis
Type paramType = paraminfos[i].Info.ParameterType;
object param = null;
if (opArg.IsDefaultArgument)
param = Type.Missing;
param = missing;
else
param = marshaller.UnMarshal(opArg, c, dsi, paramType);

Expand All @@ -559,7 +571,7 @@ public override object Execute(ProtoCore.Runtime.Context c, Interpreter dsi, Lis

}

parameters.Add(param);
parameters[i] = param;
}
catch (System.InvalidCastException ex)
{
Expand All @@ -574,7 +586,7 @@ public override object Execute(ProtoCore.Runtime.Context c, Interpreter dsi, Lis
}
}

var ret = InvokeFunctionPointerNoThrow(c, dsi, thisObject, parameters.Count > 0 ? parameters.ToArray() : null);
var ret = InvokeFunctionPointerNoThrow(c, dsi, thisObject, parameters);
if (ReflectionInfo.KeepReferenceThis && thisObject != null)
{
referencedParameters.Add(s.Last());
Expand Down
31 changes: 23 additions & 8 deletions src/Engine/ProtoCore/FFI/CLRObjectMarshaler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -504,12 +504,27 @@ public override object UnMarshal(StackValue dsObject, ProtoCore.Runtime.Context

internal static bool IsAssignableFromDictionary(Type expectedCLRType)
{
return expectedCLRType == typeof(IDictionary) ||
expectedCLRType.GetInterfaces()
.Where(i => i.IsGenericType)
.Select(i => i.GetGenericTypeDefinition())
.Contains(typeof(IDictionary<,>)) ||
expectedCLRType.IsAssignableFrom(typeof(DesignScript.Builtin.Dictionary));
if (expectedCLRType == typeof(IDictionary))
return true;

// Fast path for common generic IDictionary<,>
if (expectedCLRType.IsGenericType && expectedCLRType.GetGenericTypeDefinition() == typeof(IDictionary<,>))
return true;

// Check interfaces without LINQ
var interfaces = expectedCLRType.GetInterfaces();
for (int i = 0; i < interfaces.Length; i++)
{
var iface = interfaces[i];
if (iface.IsGenericType && iface.GetGenericTypeDefinition() == typeof(IDictionary<,>))
return true;
}

// Check assignability from DesignScript.Builtin.Dictionary
if (expectedCLRType.IsAssignableFrom(typeof(DesignScript.Builtin.Dictionary)))
return true;

return false;
}

private object ToIDictionary(StackValue dsObject, ProtoCore.Runtime.Context context, Interpreter dsi, System.Type expectedType)
Expand Down Expand Up @@ -709,9 +724,9 @@ public override StackValue Marshal(object obj, ProtoCore.Runtime.Context context
return retVal;

//5. If it is a StackValue, simply return it.
if (obj is StackValue)
if (obj is StackValue sv)
{
return (StackValue)obj;
return sv;
}

//6. Seems like a new object create a new DS object and bind it.
Expand Down
Loading
Loading