• WebAssembly 和 JavaScript 的 String 类型数据交换


    前言

    我们知道 WASM 和 HOST 环境(Browser)是通过线型内存共享空间的,所以本质上交换数据就是在这段共享内存中存和取数据,以及对数据如何编码。

    这里又涉及到对应的 WASM 产物是如何在内存中存放数据的,例如下面的案例是在内存空间直接寻址提取和存放数据的

    不同的数据结构(Array,Object,Struct)有自己的内存空间定义,所以我只针对 String 做 Case

    字符串类型

    wasm 到 js

    index.c: 其中定义 get_str_from_wasm 方法,返回字符串指针

    // wasm string pointer
    char * get_str_from_wasm(void) {
      return (char *)"Hello, From WASM";
    }
    

    Makefile: 编译

    main:
        emcc \
            index.c \
            -s ERROR_ON_UNDEFINED_SYMBOLS=0 \
            -s EXPORTED_FUNCTIONS="[_malloc,_free,_get_str_from_js]" \
            --no-entry \
            -o \
                ./index.wasm
    
    clean:
    	rm -rfv *.wasm
    

    index.html: 加载 wasm,通过1byte(8Bit)去取内存数据

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Shared</title>
    </head>
      <script type="text/javascript">
        (async function () {
          function AsciiToString(ptr, heapu8) {
            let str = '';
    
            while (1) {
              let ch = heapu8[ptr++];
              if (!ch) return str;
              str += String.fromCharCode(ch);
            }
          }
    
          const resp = await fetch(`./index.wasm?t=${Date.now()}`);
          const bytes = await resp.arrayBuffer();
          const { instance } = await WebAssembly.instantiate(bytes, {
            env: {},
          });
          // 结构化数据
          const HEAP8 = new Int8Array(instance.exports.memory.buffer);
    
          // get string from wasm
          const wasm_str_ptr = instance.exports.get_str_from_wasm();
          const wasm_str = AsciiToString(wasm_str_ptr, HEAP8);
    
          console.log(wasm_str); //Hello, From WASM
        })().catch(err => console.error(err));
      </script>
    </body>
    </html>
    

    我只用 ascii 码的形式去编码数据和解码数据,其实如果涉及到 UTF-8 类型数据,需要用 Int32Array 去取数据解码。

    js 到 wasm

    index.c: 定义 set_str_from_js 来设置字符串,get_str_from_js 来去字符串指针

    char * js_str;
    
    // set string pointer
    void set_str_from_js(char * str) {
      js_str = str;
    }
    
    // return string pointer
    char * get_str_from_js() {
      return js_str;
    }
    

    Makefile

    main:
        emcc \
            index.c \
            -s ERROR_ON_UNDEFINED_SYMBOLS=0 \
            -s EXPORTED_FUNCTIONS="[_malloc,_free,_get_str_from_wasm,_set_str_from_js]" \
            --no-entry \
            -o \
                ./index.wasm
    
    clean:
        rm -rfv *.wasm
    

    index.html 因为

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Shared</title>
    </head>
      <script type="text/javascript">
        (async function () {
          function AsciiToString(ptr, heapu8) {
            let str = '';
    
            while (1) {
              let ch = heapu8[ptr++];
              if (!ch) return str;
              str += String.fromCharCode(ch);
            }
          }
    
          const resp = await fetch(`./index.wasm?t=${Date.now()}`);
          const bytes = await resp.arrayBuffer();
          const { instance } = await WebAssembly.instantiate(bytes, {
            env: {},
          });
    
          const str = "Hello, From JS";
          const str_ptr = instance.exports.malloc(str.length);
          const HEAP8 = new Int8Array(instance.exports.memory.buffer);
    
          // 1 byte 1 byte 的形式去内存中设置值,直接修改 wasm 内存数据
          str.split('').forEach((char, index) => {
            HEAP8[(str_ptr + index) >> 0] = char.charCodeAt(0);
          });
    
          // 传递指针
          instance.exports.set_str_from_js(str_ptr);
          // 获取值
          const str_ptr_from_wasm = instance.exports.get_str_from_js();
          const str_from_wasm = AsciiToString(str_ptr_from_wasm, HEAP8);
    
          console.log(str_from_wasm); // "Hello, From JS"
    
        })().catch(err => console.error(err));
      </script>
    </body>
    </html>
    

    可以看出,string 是不能直接通过 API 形式传递,需要开辟内存空间,往对应的内存空间写数据,再把 pointer 传入到 wasm 方法去。

    其他类型数据

    其他高级类型数据和对应的存储结构有关,可以通过高阶的 wrap 形式来做传递,本质上和 String 的传递类似。

  • 相关阅读:
    Linux下C语言的调试--转
    linux下c的网络编程---转载
    redis学习资料
    Keepalived配置与使用--转载
    Redis configuration
    keepalived程序包
    Keepalived 使用指南
    myeclipse解决JSP文件script调整背景颜色
    java 面试题汇总(未完成)
    c++ primer plus(文章6版本)中国版 编程练习答案第八章
  • 原文地址:https://www.cnblogs.com/xiaoniuzai/p/15887765.html
Copyright © 2020-2023  润新知