WebAssembly - 模块

  • 简述

    我们已经了解了如何从 c /c++ 代码中获取 .wasm 文件。在本章中,我们会将 wasm 转换为 WebAssembly 模块并在浏览器中执行相同的操作。
    让我们使用如下所示的 C++ 阶乘代码 -
    
    int fact(int n) {
       if ((n==0)||(n==1))
          return 1;
       else
          return n*fact(n-1);
    }
    
    打开 https://mbebenita.github.io/WasmExplorer/ 上提供的 Wasm Explorer,如下所示 -
    C++ 阶乘函数
    第一列是 C++ 阶乘函数,第二列是 WebAssembly 文本格式,最后一列是 x86 汇编代码。
    WebAssembly 文本格式 -
    
    (module
       (table 0 anyfunc)
       (memory $0 1)
       (export "memory" (memory $0))
       (export "_Z4facti" (func $_Z4facti))
       (func $_Z4facti (; 0 ;) (param $0 i32) (result i32)
          (local $1 i32)
          (set_local $1
             (i32.const 1)
          )
          (block $label$0
             (br_if $label$0
                (i32.eq
                   (i32.or
                      (get_local $0)
                      (i32.const 1)
                   )
                   (i32.const 1)
                )
             )
             (set_local $1
                (i32.const 1)
             )
             (loop $label$1
                (set_local $1
                   (i32.mul
                      (get_local $0)
                      (get_local $1)
                   )
                )
                (br_if $label$1
                   (i32.ne
                      (i32.or
                         (tee_local $0
                            (i32.add
                               (get_local $0)
                               (i32.const -1)
                            )
                         )
                         (i32.const 1)
                      )
                      (i32.const 1)
                   )
                )
             )
          )
          (get_local $1)
       )
    )
    
    C++ 函数fact已以 WebAssembly 文本格式导出为“ _Z4facti ”。
    单击下载按钮下载 wasm 代码并将文件保存为 factorial.wasm。
    阶乘 WASM
    现在要将 .wasm 代码转换为模块,我们必须执行以下操作 -
  • 第1步

    使用ArrayBuffer 将 .wasm 转换为 arraybuffer。ArrayBuffer 对象将返回一个固定长度的二进制数据缓冲区。
  • 第2步

    必须使用WebAssembly.compile(buffer)函数将 ArrayBuffer 中的字节编译成模块。
    WebAssembly.compile()函数编译并从给定的字节返回一个 WebAssembly.Module。
    这里是第 1 步和第 2 步中讨论的 Javascript 代码。
    
    <script type="text/javascript">
       let factorial;
       fetch("factorial.wasm")
          .then(bytes => bytes.arrayBuffer())
          .then(mod => WebAssembly.compile(mod))
          .then(module => {return new WebAssembly.Instance(module) })
          .then(instance => {
          
          factorial = instance.exports._Z4facti;
          console.log('Test the output in Brower Console by using factorial(n)');
       });
    </script>
    
  • 代码说明

    • Javascript 浏览器 API fetch 用于获取 factorial.wasm 的内容。
    • 使用 arrayBuffer() 将内容转换为字节。
    • 该模块是通过调用 WebAssembly.compile(mod) 从字节创建的。
    • 模块的实例是使用 new 创建的
      WebAssembly.Instance(模块)
    • 阶乘函数 export _Z4facti 使用 WebAssembly.Module.exports() 分配给变量阶乘。
  • 例子

    在这里,是 module.html 以及 javascript 代码 -
    模块.html
    
    <!doctype html>
    <html>
       <head>
          <meta charset="utf-8">
          <title>WebAssembly Module</title>
       </head>
       <body>
          <script>
          let factorial;
          fetch("factorial.wasm")
          .then(bytes => bytes.arrayBuffer())
          .then(mod => WebAssembly.compile(mod))
          .then(module => {return new WebAssembly.Instance(module) })
          .then(instance => {
             factorial = instance.exports._Z4facti;
             console.log('Test the output in Browser Console by using factorial(n)');
          });
          </script>
       </body>
    </html>
    
  • 输出

    在浏览器中执行 module.html 以查看输出 -
    执行模块 Html