Staeff
Staeff

Reputation: 5084

WebAssembly: Correct way to get a string from a parameter (with memory address) in JavaScript

I'm trying to understand how the conversion of C code to WebAssembly and the JavaScript interop works in the background. And I'm having problems getting a simple string from a function parameter.

My program is a simple Hello World, and I'm trying to "emulate" a printf/puts.

More or less the C equivalent I want to build:

int main() {
  puts("Hello World\n");
}

You can see a working example here.

My best idea currently is to read 16bit chunks of memory at a time (since wasm seems to allocate them in 16bit intervals) and check for the null-terminaton.

function get_string(memory, addr) {
  var length = 0;

  while (true) {
    let buffer = new Uint8Array(memory.buffer, addr, 16);
    let term = buffer.indexOf(0);

    length += term == -1 ? 16 : term;

    if (term != -1) break;
  }

  const strBuf = new Uint8Array(memory.buffer, addr, length);
  return new TextDecoder().decode(strBuf);
}

But this seems really clumsy. Is there a better way to read a string from the memory if you only know the start address?

And is it really necessary that I only read 16bit chunks at a time? I couldn't find any information if creating an typed array of the memory counts as accessing the whole memory or this only happens when I try to get the data from the array.

Upvotes: 1

Views: 1134

Answers (1)

wrock
wrock

Reputation: 1349

WebAssembly allocates memory in 64k pages. Maybe this is where the 16 bit thing came from, because 16 bits can address 64 kbytes. However this is irrelevant to the task at hand, since the WebAssembly memory is just a continuous address space, there isn't much difference between the memory object and an ArrayBuffer of the given size, if there's any at all.

The 16-byte-window-at-a-time isn't necessary as well (somehow 16 bits became 16 bytes).

You can do it simply without any performance penalty and create a view of the rest of the buffer in the following way:

function get_string(memory, addr) {
  let buffer = new Uint8Array(memory.buffer, addr, memory.buffer.byteLength - addr);
  let term = buffer.indexOf(0);

  return new TextDecoder().decode(buffer.subarray(0, term));
}

Upvotes: 3

Related Questions