Assemblyscript: How to share u16/u32/f64... ect on memory?

Created on 12 Dec 2018  ·  4Comments  ·  Source: AssemblyScript/assemblyscript

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(offset)
}

export function writeMemoryU8(offset: usize, value: u8): void {
store(offset, value)
}

export function readMemoryU16(offset: usize): u16 {
return load(offset)
}

export function writeMemoryU16(offset: usize, value: u16): void {
store(offset, value)
}

export function readMemoryF64(offset: usize): f64 {
return load(offset)
}

export function writeMemoryF64(offset: usize, value: f64): void {
store(offset, value)
}

// ...

```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);

});
});

```

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 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);
}

All 4 comments

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!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

pannous picture pannous  ·  4Comments

MaxGraey picture MaxGraey  ·  3Comments

kyegupov picture kyegupov  ·  3Comments

torch2424 picture torch2424  ·  5Comments

evgenykuzyakov picture evgenykuzyakov  ·  3Comments