c语言片段

新建文件名为side_module.c的文件


int Increment(int value) {
    return value + 1;
}

int Decrement(int value) {
    return value - 1;
}

O1编译

命令

emcc side_module.c -s SIDE_MODULE=2 -O1 -s EXPORTED_FUNCTIONS='["_Increment", "_Decrement"]' -o build/side_module.wasm

SIDE_MODULE=2标记会告诉Emscripten不想在生成的模块中包含像C标准库这样的东西,也不想生成JavaScript plumbing文件。

新建html导入

将编译好的wasm文件通过js加载,内容如下:

(module
  (global $env.__memory_base (;0;) (import "env" "__memory_base") i32)
  (global $env.__table_base (;1;) (import "env" "__table_base") i32)
  (memory $env.memory (;0;) (import "env" "memory") 0)
  (func $__wasm_call_ctors (;0;) (export "__wasm_call_ctors")
  )
  (func $__wasm_apply_data_relocs (;1;) (export "__wasm_apply_data_relocs")
  )
  (func $Increment (;2;) (export "Increment") (param $var0 i32) (result i32)
    local.get $var0
    i32.const 1
    i32.add
  )
  (func $Decrement (;3;) (export "Decrement") (param $var0 i32) (result i32)
    local.get $var0
    i32.const -1
    i32.add
  )
)

此时js要正常加载,需要配置全局变量和内存,完整代码:

<script>

    let memoryBase = new WebAssembly.Global({value: 'i32'}, 1024);

    let tableBase = new WebAssembly.Global({value: 'i32'}, 1024);

    let memory = new WebAssembly.Memory({initial: 256, maximum: 256});

    const importObject = {

    env: {
            memory: memory, 
            __memory_base: memoryBase,
            __table_base: tableBase,

        }

    };

    WebAssembly.instantiateStreaming(fetch('side_module.wasm'), importObject).then(result => {

    console.log(result.instance.exports);

    const value = result.instance.exports.Increment(17);

    console.log(value);

    })

</script>

O2或O3编译

wasm内容与上面有些不同:

(module
  (func $__wasm_call_ctors (;0;) (export "__wasm_call_ctors") (export "__wasm_apply_data_relocs")
    nop
  )
  (func $Increment (;1;) (export "Increment") (param $var0 i32) (result i32)
    local.get $var0
    i32.const 1
    i32.add
  )
  (func $Decrement (;2;) (export "Decrement") (param $var0 i32) (result i32)
    local.get $var0
    i32.const 1
    i32.sub
  )
)

此时不用定义全局变量和内存就可以正常调用:

<script>
    WebAssembly.instantiateStreaming(fetch('side_module.wasm')).then(result => {

    console.log(result.instance.exports);

    const value = result.instance.exports.Increment(17);

    console.log(value);

    })

</script>

总结

选项O2O1优化更多内容,O1选择需要额外定义env配置来适配模块的全局变量和内存。模块文件分前导、已知段和自定义段,其中Table段定义函数引用数组,Memory段定义模块线性内存,相当于堆内存,Global定义全局变量。 程序运行时,操作系统会先分配内存给全局变量和函数使用,由于wasm运行在js虚拟机不能直接申请内存,只能在实例化模块时预先申请ArrayBuffer充当内存使用。 在学习阶段可以多次编译,查看wasm内容或程序的需要来决定是否需要设置env