WebAssembly:从 JavaScript 中的参数(带有内存地址)获取字符串的正确方法

Posted

技术标签:

【中文标题】WebAssembly:从 JavaScript 中的参数(带有内存地址)获取字符串的正确方法【英文标题】:WebAssembly: Correct way to get a string from a parameter (with memory address) in JavaScript 【发布时间】:2018-07-27 16:47:40 【问题描述】:

我试图了解 C 代码到 WebAssembly 的转换和 javascript 互操作是如何在后台工作的。而且我在从函数参数中获取简单字符串时遇到问题。

我的程序是一个简单的 Hello World,我正在尝试“模拟”printf/puts

或多或少是我想要构建的 C 等价物:

int main() 
  puts("Hello World\n");

您可以看到一个工作示例here。

我目前最好的想法是一次读取 16 位内存块(因为 wasm 似乎以 16 位间隔分配它们)并检查空终止。

function get_string(memory, addr) 
  var length = 0;

  while (true) 
    let buffer = new Uint8Array(memory.buffer, addr, 16);
    let term = buffer.indexOf(0);

    length += term == -1 ? 16 : term;

    if (term != -1) break;
  

  const strBuf = new Uint8Array(memory.buffer, addr, length);
  return new TextDecoder().decode(strBuf);

但这看起来真的很笨拙。如果只知道起始地址,有没有更好的方法从内存中读取字符串?

我真的有必要一次只读取 16 位块吗? 如果创建内存的类型化数组算作访问整个内存,或者仅当我尝试从数组中获取数据时才会发生这种情况,我找不到任何信息。

【问题讨论】:

Emscipten 中的胶水代码 ccall 对您有帮助吗? kripken.github.io/emscripten-site/docs/api_reference/…github.com/kripken/emscripten/blob/… 【参考方案1】:

WebAssembly 在 64k 页中分配内存。也许这就是 16 位的来源,因为 16 位可以寻址 64 KB。然而,这与手头的任务无关,因为 WebAssembly 内存只是一个连续的地址空间,memory 对象和给定大小的ArrayBuffer 之间没有太大区别,如果有的话。

一次 16 字节的窗口也不是必需的(不知何故,16 位变成了 16 字节)。

您可以简单地执行此操作而不会降低性能,并通过以下方式创建缓冲区其余部分的视图:

function get_string(memory, addr) 
  let buffer = new Uint8Array(memory.buffer, addr, memory.buffer.byteLength - addr);
  let term = buffer.indexOf(0);

  return new TextDecoder().decode(buffer.subarray(0, term));

【讨论】:

以上是关于WebAssembly:从 JavaScript 中的参数(带有内存地址)获取字符串的正确方法的主要内容,如果未能解决你的问题,请参考以下文章

如何从 WebAssembly 函数返回 JavaScript 字符串

WebAssembly:从 JavaScript 中的参数(带有内存地址)获取字符串的正确方法

如何从 JavaScript 执行 Kotlin WebAssembly 函数?

从JavaScript到TypeScript,Flow与WebAssembly

从 JS 引擎谈到 WebAssembly

第1451期在 JavaScript 和 WebAssembly 之间调用执行速度终于快了