I just use codes like MDN Example to access memory from AS and JS.
But except u8/i8, all test pattern failed and I saw data shown by JS are different from which shown by AS.
How can I store data in float?
My codes like:
```index.ts
// assembly/index.ts
export function readMemoryU8(offset: usize): u8 {
return load
}
export function writeMemoryU8(offset: usize, value: u8): void {
store
}
export function readMemoryU16(offset: usize): u16 {
return load
}
export function writeMemoryU16(offset: usize, value: u16): void {
store
}
export function readMemoryF64(offset: usize): f64 {
return load
}
export function writeMemoryF64(offset: usize, value: f64): void {
store
}
// ...
```index.js
// index.js
const fs = require("fs");
const compiled = new WebAssembly.Module(fs.readFileSync(__dirname + "/build/optimized.wasm"));
const imports = {};
Object.defineProperty(module, "exports", {
get: () => new WebAssembly.Instance(compiled, imports).exports
});
```index.test.js
// __tests__/index.test.js
const wasm = require('../index');
const memory = wasm.memory;
describe('Test WASM', () => {
beforeAll(() => {
const mem = new Uint8Array(memory.buffer);
if (mem.length < 1) {
memory.grow(1);
}
wasm.memory.grow(1);
});
test('read / write uint8', () => {
const mem = new Uint8Array(memory.buffer);
mem.set([1, 3, 5]);
console.log([0, 1, 2, 3, 4, 5].map(wasm.readMemoryU8));
// [ 1, 3, 5, 0, 0, 0 ]
console.log(mem.subarray(0, 6));
//Uint8Array [ 1, 3, 5, 0, 0, 0 ]
expect(wasm.readMemoryU8(1)).toBe(3);
wasm.writeMemoryU8(1, 6);
expect(wasm.readMemoryU8(1)).toBe(6);
expect(mem[1]).toBe(6);
expect(wasm.readMemoryU8(0)).toBe(1);
expect(wasm.readMemoryU8(2)).toBe(5);
});
test('read / write uint16', () => {
const mem = new Uint16Array(memory.buffer);
mem.set([1, 3, 257]);
console.log([0, 1, 2, 3, 4, 5].map(wasm.readMemoryU16));
// [ 1, 768, 3, 256, 257 ]
console.log(mem.subarray(0, 6));
// Uint16Array [ 1, 3, 257, 0, 0, 0 ]
expect(wasm.readMemoryU16(0)).toBe(1);
expect(wasm.readMemoryU16(1)).toBe(3); // failed
wasm.writeMemoryU16(1, 6);
expect(wasm.readMemoryU16(1)).toBe(6);
expect(mem[1]).toBe(6);
expect(wasm.readMemoryU16(2)).toBe(5);
});
test('read / write float64', () => {
const mem = new Float64Array(memory.buffer);
mem.set([1, -3.2, 25.8]);
console.log([0, 1, 2, 3, 4, 5].map(wasm.readMemoryF64));
// [ 1,
// -3.0065162379579438e-182,
// -2.413170169815393e-185,
// -2.3536706995205933e-185,
// -2.3534382797147542e-185,
// -2.3534373718248877e-185 ]
console.log(mem.subarray(0, 6));
// Float64Array [ 1, -3.2, 25.8, 0, 0, 0 ]
expect(wasm.readMemoryF64(0)).toBe(1);
expect(wasm.readMemoryF64(1)).toBe(-3.2); // failed
wasm.writeMemoryI16(1, -6.5);
expect(wasm.readMemoryF64(1)).toBe(-6.5);
expect(mem[1]).toBe(-6.5);
expect(wasm.readMemoryI16(2)).toBe(25.8);
});
});
```
Looks like the increment is always 1
for the offset, which is correct for 8-bit values, but should be 2
for 16-bit and 4
for 32-bit values etc., here resulting in a situation where values overwrite each other.
@dcodeIO
That is the very problem. when store<f64>(0, 1.5)
, then store<f64>(1, 2.7)
, In this time load<f64>(0)
will return a strange value. But load<f64>(1)
will return 2.7
.
The offset
in your case is the exact memory position, but you are passing the index, which needs to be multiplied. When using an f64
, you'll have to increment the offset by 8
bytes (this is a 64-bit value) so the values don't overwrite each other, e.g.
export function readMemoryF64(index: u32): f64 {
return load<f64>(index << alignof<f64>());
}
export function writeMemoryF64(index: u32, value: f64): void {
store<f64>(index << alignof<f64>(), value);
}
@dcodeIO
Test passed!
Thanks Very Much!
Most helpful comment
The
offset
in your case is the exact memory position, but you are passing the index, which needs to be multiplied. When using anf64
, you'll have to increment the offset by8
bytes (this is a 64-bit value) so the values don't overwrite each other, e.g.