Nicolas Marshall
Nicolas Marshall

Reputation: 4444

Wasm-bindgen: access wasm instance's memory buffer (from JS)

According to this github comment, I can re-create an Uint8ClampedArray or Uint8Array returned from Rust/wasm by accessing the memory of the wasm instance directly:

const textureRaw = new Uint8ClampedArray(memory.buffer, texture.offset(), texture.size());

The thing is, the js files generated by wasm-bindgen already instantiate a wasm instance, and I'd want to access the memory of this particular instance but it doesn't seem to be exported:

// XXXXX_bg.js

const path = require('path').join(__dirname, 'ed25519_sigs_bg.wasm');
const bytes = require('fs').readFileSync(path);
let imports = {};
imports['./ed25519_sigs.js'] = require('./ed25519_sigs.js');

const wasmModule = new WebAssembly.Module(bytes);
const wasmInstance = new WebAssembly.Instance(wasmModule, imports);
module.exports = wasmInstance.exports;

How would I access the current wasm instance's memory buffer ?

I've tried doing:

import { memory } from "XXXXXX_bg";

// say o is returned as an object with the right offset() and size() accessors. It represents an Uint8Array in memory
let outU8A: Uint8Array = new Uint8Array(
  memory.buffer,
  o.offset(),
  o.size()
);

The output is the expected size but every value is zero. Which makes me think I might be trying to load from a second wasm.memory instance ?

Upvotes: 4

Views: 1198

Answers (2)

Yilmaz
Yilmaz

Reputation: 49180

In order to send reference from Rust to Javascript we use as_ptr which is a reference to the beginning of your data type. It is a memory address. An example

// we are returning a pointer type
// *const is a raw pointer and borrowing rules do not apply
pub fn cells(&self)->*const Cell{
        // as_ptr is the reference to the first item in the vector
        // assume that body:Vec<Cell>
        self.body.as_ptr()
    }

in the example, I am sending a reference to the beginning of the vector type. You could also write a function to return the lenght of the vector.

// init().then((wasm) => {} initilaization of js code is like this. 
const cells = new Uint32Array(
   // with memory.buffer you can access to the pointer
   wasm.memory.buffer,
   o.offset(),
   o.size()
); 

Upvotes: 1

birneee
birneee

Reputation: 663

import { memory } from "XXXXXX_bg";

This memory import should work fine, but I guess you try to access freed memory. Although I do not know why freed memory appears as zeros immediately.

I created a short working example, by using static memory:

#[wasm_bindgen]
pub unsafe fn static_value() -> ByteStream {
    static mut values: [u8; 3] = [0; 3];
    let slice = values.as_mut_slice();
    slice.copy_from_slice(&[1, 2, 3]); // fill with some data
    ByteStream::new(slice)
}

Accessing the freed memory of the following code does not work:

#[wasm_bindgen]
pub fn freed_heap_value() -> ByteStream {
    let mut values = Box::new([0; 3]);
    let slice = values.as_mut_slice();
    slice.copy_from_slice(&[1, 2, 3]); // fill with some data
    ByteStream::new(slice)
}

Depending on your use case, you could also free the heap allocation manually afterwards:

#[wasm_bindgen]
pub fn heap_value() -> ByteStream {
    let mut values = Box::new([0; 3]);
    let values = Box::leak(values); // has to be freed manually
    let slice = values.as_mut_slice();
    slice.copy_from_slice(&[1, 2, 3]); // fill with some data
    ByteStream::new(slice)
}

Upvotes: 0

Related Questions