xgqfrms™, xgqfrms® : xgqfrms's offical website of cnblogs! xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!

WebAssembly JS API All In One

WebAssembly JS API All In One

在 js 中执行 .wasm 文件的步骤


(() => {
  const log = console.log;
  log(`\n🎉在 js 中执行 \`.wasm\` 文件的4个步骤: `);
  const ThrowErrorInfo = () => {
    throw new Error(`fetch WASM failed!`);
  };
  const WASM_URL = `https://cdn.xgqfrms.xyz/webassembly/math-sqrt-demo.wasm`;
  fetch(WASM_URL)
  .then(res => {
    // 1. 获取 wasm 转换成 ArrayBuffer 形式的 bytes 字节码
    log(`1. 获取 wasm 转换成 ArrayBuffer 形式的 bytes 字节码`);
    return res.ok ? res.arrayBuffer() : ThrowErrorInfo();
  })
  .then(bytes => {
    // async / await: WebAssembly.compile
    // 2. 使用 WebAssembly.compile 把 bytes 字节码编译成 module 模块
    log(`2. 使用 WebAssembly.compile 把 bytes 字节码编译成 module 模块`);
    return WebAssembly.compile(bytes);
  })
  .then(module => {
    // async / await: WebAssembly.instantiate
    // 3. 使用 WebAssembly.instantiate 把 module 模块实例化,并把模块中定义的方法 exports 导出
    log(`3. 使用 WebAssembly.instantiate 把 module 模块实例化,并把模块中定义的方法 exports 导出`)
    return WebAssembly.instantiate(module);
  })
  .then(instance => {
    // 4. 导入模块 exports 的方法
    log(`4. 导入模块 exports 的方法`);
    const {sqrt} = instance.exports;
    // global namespace (WebAssembly)
    if(!window.WebAssembly) {
      WebAssembly = {};
    }
    window.WebAssembly.sqrt = sqrt;
    console.log('\nsqrt(4) =', sqrt(4), sqrt(4) === 2 ? `✅` : `❌`);
    // sqrt(4) = 2 ✅
    console.log('\nWebAssembly.sqrt(4) =', WebAssembly.sqrt(4), WebAssembly.sqrt(4) === 2 ? `✅` : `❌`);
    // WebAssembly.sqrt(4) = 2 ✅
  });
})();

/*

🎉在 js 执行 `.wasm` 文件的4个步骤: 

1. 获取 wasm 转换成 ArrayBuffer 形式的 bytes 字节码
2. 使用 WebAssembly.compile 把 bytes 字节码编译成 module 模块
3. 使用 WebAssembly.instantiate 把 module 模块实例化,并把模块中定义的方法 exports 导出
4. 导入模块 exports 的方法

sqrt(4) = 2 ✅

WebAssembly.sqrt(4) = 2 ✅

*/

test

https://cdn.xgqfrms.xyz/index.html

demo

https://cdn.xgqfrms.xyz/webassembly/index.html

https://cdn.xgqfrms.xyz/webassembly/math-sqrt-demo.wasm

https://cdn.xgqfrms.xyz/webassembly/math-sqrt-demo.wast

https://cdn.xgqfrms.xyz/webassembly/math-sqrt-demo.wat


;; author xgqfrms, 2022.09.01
;; 编译器

;; C/C++ => WASM (.c/.cpp => .wasm)
;; https://mbebenita.github.io/WasmExplorer/

;; WAT/WAST => WASM (.wat/.wast => .wasm)
;; https://webassembly.github.io/wabt/demo/wat2wasm/

;; Rust => WASM (.rs => .wasm)
;; https://github.com/yewstack/yew
;; https://developer.mozilla.org/en-US/docs/WebAssembly/Rust_to_wasm


;; WebAssembly text format
;; To enable WebAssembly to be read and edited by humans, there is a textual representation of the wasm binary format.
;; 为了使 WebAssembly 能够被人类阅读和编辑,有一个 wasm 二进制格式的文本表示。

;; js's Math.sqrt(4) === 2
;; wat define method `sqrt`
(module
    (export "sqrt" (func $sqrt))
    (func $sqrt
        (param $num f32)
        (result f32)
        ;; get_local ❌ WebAssembly draft
        ;; (f32.sqrt (get_local $num))
        ;; local.get ✅ WebAssembly Specification
        (f32.sqrt (local.get $num))
    )
)



WebAseembly imports & exports

;; simple.wat => simple.wasm
;; simple.wast => simple.wasm
;; 使用 s-expr, 手动组装 WebAssembly Module
(module
  (func $getYear (import "imports" "getYear") (param i32))
  (func (export "printYear")
    ;; 写死 const
    i32.const 2022
    call $getYear
  )
)

pass param ✅

;; simple-arg.wat
;; local.get
(module
  (func $getYear (import "imports" "getYear") (param i32))
  (func (export "printYear") (param $year i32)
    (call $getYear(local.get $year))
  )
)



// 2 和 1, 实例化
function instantiate(bytes, imports) {
  return WebAssembly.compile(bytes).then(module => new WebAssembly.Instance(module, imports));
}

// two-level namespaces relfect
// 定义 imports 映射对象
const importObject = {
  imports: {
    getYear: year => console.log(`🎉 🇨🇳 🗓 this year is ${year}`),
  }
};


fetch('https://cdn.xgqfrms.xyz/webassembly/imports-exports/simple.wasm')
// fetch('https://cdn.xgqfrms.xyz/webassembly/imports-exports/simple-arg.wasm')
// fetch('simple.wasm')
.then(response => response.arrayBuffer())
.then(bytes => instantiate(bytes, importObject))
.then(instance => {
  const {printYear} = instance.exports;
  printYear();
});

// console.log(`🎉 🇨🇳 🗓 this year is ${year}`)

// 2 和 1, 实例化
function instantiate(bytes, imports) {
  return WebAssembly.compile(bytes).then(module => new WebAssembly.Instance(module, imports));
}

// two-level namespaces relfect
// 定义 imports 映射对象
const importObject = {
  imports: {
    getYear: year => console.log(`🎉 🇨🇳 🗓 this year is ${year}`),
  }
};


// fetch('https://cdn.xgqfrms.xyz/webassembly/imports-exports/simple.wasm')
fetch('https://cdn.xgqfrms.xyz/webassembly/imports-exports/simple-arg.wasm')
// fetch('simple.wasm')
.then(response => response.arrayBuffer())
.then(bytes => instantiate(bytes, importObject))
.then(instance => {
  const {printYear} = instance.exports;
  const year = new Date().getFullYear();
  printYear(year);
});

// console.log(`🎉 🇨🇳 🗓 this year is ${year}`)

https://cdn.xgqfrms.xyz/webassembly/imports-exports/simple.wat

https://cdn.xgqfrms.xyz/webassembly/imports-exports/simple-arg.wat

https://cdn.xgqfrms.xyz/webassembly/imports-exports/simple.wasm

https://cdn.xgqfrms.xyz/webassembly/imports-exports/simple-arg.wasm

wat2wasm

https://webassembly.github.io/wabt/demo/wat2wasm/

WebAssembly.Memory & ArrayBuffer

bytes 字节码

the unit of initial and maximum is WebAssembly pages which are fixed to be 64KB.

// memory has an initial size of 10 pages, or `640KB` and a maximum size of `6400KB`, 即 `6.4MB`.
let memory = new WebAssembly.Memory({
  initial: 10,
  maximum:100,
});

// 赋值
// new Uint32Array(memory.buffer)[0] = 42;
const typedArray = new Uint32Array(memory.buffer);
typedArray[0] = 42;


// If a maximum is supplied upon creation attempts to grow past this maximum will throw a `RangeError` exception.
// pages + 1
memory.grow(1);


Just like functions, linear memories can be defined inside a module or imported. Similarly, a module may also optionally export its memory.
This means that JavaScript can get access to the memory of a WebAssembly instance either by creating a new WebAssembly.Memory and passing it in as an import or by receiving a Memory export.

就像函数一样,线性存储器可以在模块内部定义或导入。类似地,一个模块也可以选择导出它的内存。
这意味着 JavaScript 可以通过创建新的 WebAssembly.Memory 并将其作为导入或通过接收内存导出来访问 WebAssembly 实例的内存。

(module
  ;; 导出 memory, memo 线性存储器
  (memory (export "mem") 1)
  ;; 导出 func, accumulate 积累/累加求和
  (func (export "accumulate") (param $ptr i32) (param $length i32) …)
  ;; ...  省略了具体的方法体实现
  ;; (local.get($ptr))
  ;; (local.get($length))
)

// 获取 memo,转换成 TypedArray / ArrayBuffer
let i32ArrayBuffer = new Uint32Array(instance.exports.mem);

for (let i = 0; i < 10; i++) {
  // 赋值, ??? memory 是引用类型
  i32ArrayBuffer[i] = i;
}

// 传参数, 执行 accumulate 
const sum = instance.exports.accumulate(0, 10);

// ???
// const {accumulate} = instance.exports;

Memory imports are useful for two reasons:

  1. They allow JavaScript to fetch and create the initial contents of memory before or concurrent with module compilation.
  2. They allow a single Memory object to be imported by multiple instances, which is a critical building block for implementing dynamic linking in WebAssembly.

内存导入很有用有两个原因:

  1. 它们允许 JavaScript 在模块编译之前或编译同时获取和创建内存的初始内容。
  2. 它们允许多个实例导入单个 Memory 对象,这是在 WebAssembly 中实现动态链接的关键构建块。

linear memory / arrayBuffer / TypedArray

https://webassembly.org/docs/semantics/#linear-memory

https://webassembly.org/docs/dynamic-linking

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays

A TypedArray object describes an array-like view of an underlying binary data buffer.
TypedArray 对象描述了底层二进制数据缓冲区类数组视图

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray

The ArrayBuffer object is used to represent a generic, fixed-length raw binary data buffer.
ArrayBuffer 对象用于表示一个通用的、固定长度的原始二进制数据缓冲区

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer

refs

https://webassembly.org/getting-started/js-api/

https://developer.mozilla.org/zh-CN/docs/WebAssembly/Loading_and_running



©xgqfrms 2012-2020

www.cnblogs.com/xgqfrms 发布文章使用:只允许注册用户才可以访问!

原创文章,版权所有©️xgqfrms, 禁止转载 🈲️,侵权必究⚠️!


posted @ 2022-09-07 08:51  xgqfrms  阅读(73)  评论(3编辑  收藏  举报