How do I access compiled memory in WebAssembly from js

1.7k views Asked by At

Consider the following C++ :

int MYVAR = 8;

It will compile from Clang/LLVM to the WASM bytecode inserted in the playground below.

WAST for readability :

(module
(table (;0;) 0 anyfunc)
(memory (;0;) 1)
(global (;0;) i32 (i32.const 0))
(export "MYVAR" (global 0))
(data (i32.const 0) "\08\00\00\00"))

MYVAR will expose a pointer to the variable when called from js.

But how do I access the actual memory with the new js API?

The memory constructor seems to erase the entry when initialising, but I´m not sure if I´m interpreting this correctly.

As a side note the Module does not have an exports property as specified in the specs, but this, again, might be a misinterpretation.

Playground:

<!doctype html>
<html>

<head>
<meta charset="utf-8">
<title>MEMORY ACCESS TEST</title>
</head> 
<div>
<h1 style="display: inline;">MEMORY LOCATION : </h1>
<h1 id='POINTER' style="display: inline;"></h1>
</div> 
<div>
<h1 style="display: inline;">VALUE : </h1>
<h1 id='VALUE' style="display: inline;"></h1>
</div>
<body>
<script>
 var bytecode = new Uint8Array([
 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x04, 0x84,
 0x80, 0x80, 0x80, 0x00, 0x01, 0x70, 0x00, 0x00, 0x05, 0x83,
 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x01, 0x06, 0x86, 0x80,
 0x80, 0x80, 0x00, 0x01, 0x7F, 0x00, 0x41, 0x00, 0x0B, 0x07,
 0x89, 0x80, 0x80, 0x80, 0x00, 0x01, 0x05, 0x4D, 0x59, 0x56,
 0x41, 0x52, 0x03, 0x00, 0x0B, 0x8A, 0x80, 0x80, 0x80, 0x00,
 0x01, 0x00, 0x41, 0x00, 0x0B, 0x04, 0x08, 0x00, 0x00, 0x00,
 0x00, 0x96, 0x80, 0x80, 0x80, 0x00, 0x07, 0x6C, 0x69, 0x6E,
 0x6B, 0x69, 0x6E, 0x67, 0x03, 0x81, 0x80, 0x80, 0x80, 0x00,
 0x04, 0x04, 0x81, 0x80, 0x80, 0x80, 0x00, 0x04
 ]);
 WebAssembly.instantiate(bytecode).then(function(wasm) {
 console.log(wasm.module);
 console.log(wasm.instance);
 let pointer = wasm.instance.exports.MYVAR;
 document.getElementById('POINTER').innerHTML = pointer; 
 let memory = new WebAssembly.Memory({initial : 1});
 let intView = new Uint32Array(memory.buffer);
 document.getElementById('VALUE').innerHTML = intView[pointer];
 });
 </script>
 </body>

 </html>
1

There are 1 answers

2
JF Bastien On BEST ANSWER

MYVAR is a global. That's a totally separate addressable unit from the Memory section. It contains individual scalar values.

You seem to be trying to access the Memory section instead. You can indeed use an i32 global as a pointer, as you could any other i32, but it can't access the Memory automagically. You have to export your memory too!

Try:

(module
(table (;0;) 0 anyfunc)
(memory (;0;) 1)
(global (;0;) i32 (i32.const 0))
(export "MYVAR" (global 0))
(export "MYMEM" (memory 0)) ;; New!
(data (i32.const 0) "\08\00\00\00"))

And:

WebAssembly.instantiate(bytecode).then(function(wasm) {
 console.log(wasm.module);
 console.log(wasm.instance);
 let pointer = wasm.instance.exports.MYVAR;
 document.getElementById('POINTER').innerHTML = pointer; 
 let memory = wasm.instance.exports.MYMEM; // New!!
 let intView = new Uint32Array(memory.buffer);
 document.getElementById('VALUE').innerHTML = intView[pointer];
 });