Closed callendorph closed 1 year ago
Yeah, it is a known limitation that you cannot get an address of a local variable. At different times a local variable can be located in different registers or in different stack frame slots.
Thank you isolating the bug. The limitation is known, but we need to fix lack of error message that is generated.
There are two workarounds you can use for connecting to C functions that return results in this way.
1) Use global variables instead of local variable.
lostanza var MINV:double = 0.0
lostanza var MAXV:double = 0.0
public lostanza defn simple-minmax () -> ref<False> :
val ret = call-c simple_minmax(addr(MINV), addr(MAXV))
return false
This will work in the vast majority of cases.
2) Use heap-allocated boxes to store the results.
lostanza deftype DoubleBox :
var value:double
public lostanza defn simple-minmax () -> ref<False> :
val minv = new DoubleBox{0.0}
val maxv = new DoubleBox{0.0}
val ret = call-c simple_minmax(addr!(minv.value), addr!(maxv.value))
return false
This is only necessary in the rare case where you expect the C function to call back into Stanza which then calls the same C function again. In that case, global variables won't work because they will get overwritten on the second time the C function is called.
Got it - I was able to work around.
This is only necessary in the rare case where you expect the C function to call back into Stanza which then calls the same C function again. In that case, global variables won't work because they will get overwritten on the second time the C function is called.
I think this more generally applies to any function that you expect to be reentrant, correct ?
Yes that's right. It's for any reentrant function.
Alright - so I got that work around to compile - but I have a slightly tangential question. I used the following approach:
extern gsl_vector_minmax : (ptr<?>, ptr<?>, ptr<?>) -> int
lostanza deftype GVMinMaxDouble:
var minV:double
var maxV:double
public lostanza defn gsl-vector-minmax (A:ref<GVector>) -> ref<Tuple> :
val mm = new GVMinMaxDouble{0.0, 0.0}
call-c gsl_vector_minmax(A.value, addr!(mm.minV), addr!(mm.maxV))
val ret = new Tuple{2}
ret.items[0] = new Double{mm.minV}
ret.items[1] = new Double{mm.maxV}
return ret
public defn minmax (A:GVector) -> Tuple :
gsl-vector-minmax(A)
Then I tried to use this in a unit test:
deftest gsl-minmax-vector-operator :
val A = GVector(3)
set-all(A, 1.0)
A[1] = 0.5
A[2] = -1.0
val res = minmax(A)
val minV = res[0]
val maxV = res[1]
; This does not work with the result object
; val [minV2, maxV2] = res
#EXPECT(minV == -1.0)
#EXPECT(maxV == 1.0)
I can unpack the returned tuple object with explicit get
operations without issue.
If I attempt to unpack the tuple with the val [minV2, maxV2] = res
line - the compiler throws this error:
tests/GVector_tests.stanza:251.23: Cannot deconstruct expression of type Tuple<?> into tuple of
length 2.
So are the lostanza Tuple<?>
and the hi-stanza tuple different objects?
Is there a way to convert between the two ?
Hi Carl,
That's pretty close. You just have to return a tuple of finite length by casting it explicitly.
public lostanza defn gsl-vector-minmax (A:ref<GVector>) -> ref<[Double,Double]> :
val mm = new GVMinMaxDouble{0.0, 0.0}
call-c gsl_vector_minmax(A.value, addr!(mm.minV), addr!(mm.maxV))
val ret = core/void-tuple(2)
ret.items[0] = new Double{mm.minV}
ret.items[1] = new Double{mm.maxV}
return ret as ref<[Double, Double]>
The above should work for what you want to do.
The only other change is calling core/void-tuple
instead of using
new Tuple{...}
directly. The reason why is that, for performance
reasons, the LoStanza new
operator does not automatically initialize
the memory of a variable-sized struct. This means it is your
responsibility to ensure that the struct is fully initialized
before running any code that may trigger the GC. These are
low-level concerns, so it's easier to just call void-tuple
,
which will initialize all the fields of tuple for you.
Got it - thank you!
This error case of FATAL ERROR: No appropriate branch for arguments of type (Int).
is extraordinarily difficult to debug. Do you have any suggestions on how to determine the cause of this error in a sane way. I've attempted to looking at the -verbose
flag output and there isn't really anything there. I basically had to start just commenting out large sections of code until I could find the culprit. From a developer productivity perspective - this error is a nightmare.
Hi,
I'm trying to write a lostanza wrapper around the gsl_vector_minmax function. This function takes a pointer to the underlying vector and then two additional pointers to doubles to store the resulting min and max values. In the process of trying to build the wrapper, the compiler seems to fault out.
I've created a small test case:
lostanza_ptrprob.zip
When I attempt to build this with
stanza build
I get this stack trace: https://gist.github.com/callendorph/2bbb7ef2bcfc461bdba3e797ec6ae2d6I'm running the linux stanza v0.17.35 in WSL in windows.
Thoughts ?