I've been fixing issues related to our Web builds and I came across something strange (in terms of the code generated).
We have this call to hash: https://github.com/arturo-lang/arturo/blob/c873dec7accc58ae0ffbab1345fe94f35db94786/src/vm/eval.nim#L563
root is a Value (which is a ref object)
And the hash to be used is here: https://github.com/arturo-lang/arturo/blob/c873dec7accc58ae0ffbab1345fe94f35db94786/src/vm/values/value.nim#L1151
I kept getting an undefined reference for the value inside hash so I decided to investigate the issue a bit more. Basically, the passed object to hash was not nil, while hash kept seeing it as nil.
My discovery is that the code generate for hash is a bit peculiar:
function hash_1644167535(v_1644167536) {
// unrelated code
var result_1644177936 = 0;
rawEcho([226,154,160,239,184,143,32,105,110,32,72,65,83,72]);
if ((v_1644167536[0] == null)) {
rawEcho([86,32,105,115,32,78,73,76,33,33,33]);
}
rawEcho(([118,46,107,105,110,100,32,61,32] || []).concat(reprEnum(v_1644167536[0].kind, NTI2113929226) || []));
result_1644177936 = hash_1644177943(v_1644167536[0].kind);
switch (v_1644167536[0].kind) {
case 0:
break;
case 1:
result_1644177936 = HEX21HEX26_1207959555(result_1644177936, SetMinus(v_1644167536[0].flags, NonLogicalF_1845493823));
break;
// more code...
Basically, the passed parameter (v_1644167536) is accessed continuously via v_1644167536[0] (as if it was an array!). When I - manually - changed all references from v_1644167536[0] to v_1644167536, it's working fine.
Can you please tell me if it's actually a bug and/or what I could do to circumvent this?
P.S. I can obviously open an issue, but I have to make sure it is what I think it is. Also, given that the codebase is practically vast, it seems as if it's the only case where this is happening. Could it be hash? Does it receive any special treatment that confuses the compiler?
That's exactly what I imagined initially (that it was a hack to access the pointer), but it appears as if it's the only case where this happens.
I've checked different functions taking a Value as a param, and it's normally accessed directly (in terms of generated code). So, I'm wondering what it is about this specific function that leads to this...
To provide some background: in order to allow indirectly modifying a variable that is of value type in the final JavaScript code, the code generator "boxes" the value by turning it into a 1-element array.
Examples of indirect modifications:
proc p(x: var int) =
x = 2
proc test() =
var i = 0
var pointerToI = addr i
pointerToI[] = 1 # an indirect modification
doAssert i == 1 # it needs to be observable on `i`
p(i) # also an indirect modification
doAssert i == 2
test()
When reading from or assigning to the location normally, the underlying value is accessed via location[0]. When taking the address of the boxed location, the box (i.e., 1-element array) itself is assigned to the pointer (not entirely true, but that's roughly how it work).
Only variables that are potentially modified through an indirection store a "boxed" value. The compiler figures out the set of variables by analyzing all addr operands, hidden address-of operands, and arguments to var parameters.
The concrete problem your running into here is that an immutable parameter cannot be promoted to use a boxed value. Since v has its address taken, whenever emitting an access to v, it is, incorrectly, unboxed, thus resulting in errors at run-time.
For fixing this bug in the compiler, there are two possible solutions: