`stdLambda` `stack` issue
sancarn opened this issue · 0 comments
Currently in evaluate
:
Case iType.oAccess
Select Case op.subType
Case ISubType.argument
Dim iArgIndex As Long: iArgIndex = val(mid(op.value, 2)) + LBound(vLastArgs) - 1
If iArgIndex <= UBound(vLastArgs) Then
Call pushV(stack, stackPtr, vLastArgs(iArgIndex))
Else
Call Throw("Argument " & iArgIndex & " not supplied to Lambda.")
End If
Case Else
Call pushV(stack, stackPtr, stack(stackPtr - op.value))
Call pushV(stack, stackPtr, stack(stackPtr - op.value))
can sometimes error when the variable at stack(stackPtr - op.value)
is an object. See explanation for details. As a temporary work around we can do the following:
'@FIX bug where if stack(stackPtr-op.value) was an object, then array will become locked. Array locking occurs by compiler to try to protect
'instances when re-allocation would move the array, and thus corrupt the pointers. By copying the variant we redivert the compiler's efforts,
'but we might actually open ourselves to errors...
Dim vAccessVar: Call CopyVariant(vAccessVar, stack(stackPtr - op.value))
Call pushV(stack, stackPtr, vAccessVar)
This may still break so we need to consider a better solution. Our suggestion is to use a Collection
(i.e. linked list) instead of a dynamic array. This should have fewer issues but might sacrifice on some performance.
Explanation:
Minimal examples where error occurs:
Sub Example()
'Initialize the array with 3 elements
Dim myArray() As string
ReDim myArray(0)
Set myArray(0) = "yop"
Call Push(myArray, myArray(0))
End Sub
Sub Push(ByRef myArray() As string, ByRef element As string)
'Lock the array to prevent deallocation of memory for the reference parameter
ReDim Preserve myArray(UBound(myArray) + 1)
If IsObject(element) Then
Set myArray(UBound(myArray)) = element
Else
myArray(UBound(myArray)) = element
End If
End Sub
The issue is that element
, in this case is a reference to an element within myArray
... The solution to above is change element
to ByVal
:
Sub Push(ByRef myArray() As string, ByVal element As string)
When extended to the variant case however:
Sub Push(ByRef myArray() As variant, ByVal element As variant)
Objects are also pointers... so
Sub Example()
'Initialize the array with 3 elements
Dim myArray() As Variant
ReDim myArray(0)
Set myArray(0) = CreateObject("scripting.dictionary")
Call Push(myArray, myArray(0))
End Sub
Sub Push(ByRef myArray() As Variant, ByVal element As Variant)
'Lock the array to prevent deallocation of memory for the reference parameter
ReDim Preserve myArray(UBound(myArray) + 1)
If IsObject(element) Then
Set myArray(UBound(myArray)) = element
Else
myArray(UBound(myArray)) = element
End If
End Sub
Also errors because we have a pointer directly to myArray(0) object. So the real work around is
Sub Example()
'Initialize the array with 3 elements
Dim myArray() As Variant
ReDim myArray(0)
Set myArray(0) = CreateObject("scripting.dictionary")
Dim v: CopyVariant(v, myArray(0))
Call Push(myArray, v)
End Sub