WASM output: TOTAL_STACK unnecessary?

498 views
Skip to first unread message

Bas van Meurs

unread,
Sep 26, 2017, 3:57:31 AM9/26/17
to emscripten-discuss
I've started to study both WASM and emscripten some time ago. My aim is to improve performance of a GL framework on an embedded box with low CPU and low memory.

Something that I don't understand is how the stack is related to the linear memory. I'd think that it may be implementation specific and that is confirmed by the Emscripten TOTAL_STACK parameter. I can follow the idea completely for asm.js, but for WASM, I am confused by an example on the MDN pages.

The MDN pages about the WASM subject show the following example (https://developer.mozilla.org/en-US/docs/WebAssembly/Understanding_the_text_format):
(module
  (import "console" "log" (func $log (param i32 i32)))
  (import "js" "mem" (memory 1))
  (data (i32.const 0) "Hi")
  (func (export "writeHi")
    i32.const 0  ;; pass offset 0 to log
    i32.const 2  ;; pass length 2 to log
    call $log))

Basically, it just writes the "Hi" string to memory offset 0 where, I'd think, the WASM stack should reside. This example works however, and also my own observation is that, when setting TOTAL_STACK to 0, the WASM output actually works fine!

main.cpp:
#include <string.h>


struct ViewCore {
 
float x;
 
float y;
 
float a;
 
float b;
 
float c;
 
float d;
};


struct ViewCore viewCores[100];


int main() {
  viewCores
[0].x = 0;
  viewCores
[0].y = 0;
  viewCores
[0].a = 1;
  viewCores
[0].b = 0;
  viewCores
[0].c = 0;
  viewCores
[0].d = 1;
 
for (int i = 1; i < 100; i++) {
    memcpy
(&viewCores[i], &viewCores[0], sizeof(ViewCore));
 
}


 
return viewCores[5].a;
}



Command to build: 
emcc main.cpp -O1 -s WASM=1 -s SIDE_MODULE=1 -s TOTAL_STACK=0 -o adder.wasm

When studying the WAST file I notice that memory is written and loaded from offset 0, as would be expected when setting TOTAL_STACK to 0:
(module
 
(type $0 (func (result i32)))
 
(type $1 (func))
 
(import "env" "memoryBase" (global $import$0 i32))
 
(import "env" "memory" (memory $0 256))
 
(import "env" "table" (table 0 anyfunc))
 
(import "env" "tableBase" (global $import$3 i32))
 
(global $global$0 i32 (i32.const 0))
 
(export "__post_instantiate" (func $2))
 
(export "_main" (func $0))
 
(export "runPostSets" (func $1))
 
(export "_viewCores" (global $global$0))
 
(func $0 (type $0) (result i32)
 
(local $var$0 i32)
 
(local $var$1 i32)
 
(f32.store
   
(get_global $import$0)
   
(f32.const 0)
 
)
 
(f32.store offset=4
   
(get_global $import$0)
   
(f32.const 0)
 
)
....


Then I try running the thing with Nodejs (8.5):
const WA = WebAssembly,
      env
= {
      memoryBase
: 0,
             tableBase
: 0,
             memory
: new WA.Memory({initial: 20}),
             table
: new WA.Table({initial: 0, element: 'anyfunc'})},
      code
= new Uint8Array(require('fs').readFileSync('adder.wasm'))
WA
.compile(code).then(m => {
   
return new WA.Instance(m, {env: env})
}).then(i => {
    console
.log(i.exports._main())
    console
.log(env.memory.buffer)
})


And it runs without problem with the correct output (1).

My main questions:
  • Is setting the stack for WASM output unnecessary / a waste of memory?
  • Shouldn't we automatically disable the stack for WASM output?
  • How is, in the case of WASM, stack layed out in memory? What is the size of it and is it controllable at all? Couldn't find it on http://webassembly.org/docs/semantics/ or MDN, so I'm hoping for your ideas.

Alon Zakai

unread,
Sep 26, 2017, 7:40:26 PM9/26/17
to emscripten-discuss
The stack defined by TOTAL_STACK etc. is the "C stack", which is just for variables whose address is taken etc., otherwise the call stack and local variables and so forth are handled by the VM automatically. So the size of the stack emscripten allocates can usually be much smaller than the stack a native program would. And some programs don't need a C stack at all (but any large C/C++ program almost certainly does).

Concretely, in emscripten the stack is basically a slice of memory, starting at STACK_BASE and extending to STACK_MAX (you can look for those JS variables in the JS code emitted by emcc, to see how they are used). It's normally after static allocations and before dynamic allocations.



--
You received this message because you are subscribed to the Google Groups "emscripten-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-discuss+unsub...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages