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.
(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)
)
....
And it runs without problem with the correct output (1).