0

I have the following C struct

typedef struct {
    ValueType type;
    union {
        bool boolean;
        double number;
        Obj* obj;
    } as;
} Value;

where ValueType is an enum as follows

typedef enum {
    VALUE_BOOL,
    VALUE_NIL,
    VALUE_NUMBER,
    VALUE_OBJ
} ValueType;

Using WASM, I define an external JS file called js_library.js within which is a function called accessStruct with the following signature defined in C.

extern void accessStruct(Value value);

I implement the function in JS as follows

function accessStruct(value) {
  console.log(Module.getValue(value, "i32"));
}

I can accurately log the value of the ValueType field as an integer. However, I was under the impression that if I simply increment the pointer by the required offset, I could access the remaining struct fields since they need to be laid out next to each other in memory, in the order specified.

So, I tried

function accessStruct(value) {
  console.log(Module.getValue(value, "i32"));
  const v = value + 32;
  console.log(Module.getValue(v, "i64"));
}

ValueType occupies 4 bytes = 32 bits. If the ValueType is a double, I should be able to access the double value through the Module.getValue(v, "i64"); line of code but I get garbage back.

Where am I going wrong?

random_coder_101
  • 1,782
  • 3
  • 24
  • 50
  • What do you think a `double` looks like when you pretend it's an `i64`? – user253751 Oct 20 '22 at 20:23
  • if you write something like `union {int64_t i; double d;}; d = 1234.5678;` and then print `i` you get garbage, don't you? – user253751 Oct 20 '22 at 20:23
  • @user253751 - I understood `i32` & `i64` to respectively refer to memory that occupies 32 bits and 64 bits. So, in C `ints` occupy 4 bytes and `doubles` occupy 8 bytes. Which is why I used `i64` to decode the double. Regarding your second comment, I thought unions occupy the same space in memory. The only thing that needs to change is how many bytes I read starting at the beginning of the union to read diff data types, no? – random_coder_101 Oct 21 '22 at 06:07
  • Both i64 and double contain 64 bits, but the bits mean different things – user253751 Oct 21 '22 at 14:16

1 Answers1

0

The getValue function expects its first argument to be the offset in bytes. The second argument is the data type. You need "double" in this case, as per the documentation.

The const v = value + 32; seems to be in bits, but you need bytes. To get the offset of a field from the start of the structure (in bytes) use something like this. You have to probably write some function in the C++ side to return you the offset and then in the JavaScript side do:

function accessStruct(offset) {
  console.log(Module.getValue(offset, "i32"));
  console.log(Module.getValue(offset + offsetToValue(), "double"));
}

You have to also ensure that the memory addressing is 32 bits. It seems that you can use "*" instead of "i32", as per the documentation, to support the 64 bits of memory addressing. Maybe you can also use a pointer to the instance as well: extern void accessStruct(Value * value);

Nikolay Handzhiyski
  • 1,360
  • 1
  • 6
  • 20
  • Passing a struct to JS, decays that struct into an int value which is a pointer to the beginning of the struct. So, I'm not sure what difference it would make to pass the pointer, except having to call `getValue` twice in succession. As for the offset, if it is in bytes, adding 1 to the value should then give me the double value since the space occupied by the ValueType enum is 1 byte but doesn't seem to work. – random_coder_101 Oct 21 '22 at 08:48
  • Its more probable that the double is aligned to 8 bytes. The pointer you currently have shall be to a temporal copy of the struct, not to the original struct. – Nikolay Handzhiyski Oct 21 '22 at 12:00