簡體   English   中英

如何將ArrayBuffer從JS傳遞給AssemblyScript / Wasm?

[英]How can I pass an ArrayBuffer from JS to AssemblyScript/Wasm?

我有一個非常簡單的Typescript代碼解析特定的數據格式,輸入是一個UInt8Array。 我已經盡可能優化了它,但我認為這個相當簡單的解析器應該能夠比我以JS運行的速度運行得更快。 我想嘗試使用AssemblyScript在Web程序集中編寫它,以確保我沒有遇到任何Javascript引擎的怪癖。

正如我現在想的那樣,我不能只將TypedArray傳遞給Wasm並讓它自動運行。 據我所知,我可以傳遞指向數組的指針,並且應該能夠直接從Wasm訪問它而無需復制數組。 但我無法使用AssemblyScript。

以下是一個最小的例子,展示了我如何將ArrayBuffer傳遞給Wasm。

設置Wasm導出的代碼主要來自自動生成的樣板:

const fs = require("fs");
const compiled = new WebAssembly.Module(
  fs.readFileSync(__dirname + "/build/optimized.wasm")
);
const imports = {
  env: {
    abort(msgPtr, filePtr, line, column) {
      throw new Error(`index.ts: abort at [${line}:${column}]`);
    }
  }
};
Object.defineProperty(module, "exports", {
  get: () => new WebAssembly.Instance(compiled, imports).exports
});

以下代碼調用WASM,index.js是上面的粘合代碼。

const m = require("./index.js");
const data = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
const result = m.parse(data.buffer);

編譯為WASM的AssemblyScript如下:

import "allocator/arena";

export function parse(offset: usize): number {
  return load<u8>(offset);
}

當我執行該代碼時,我得到一個“RuntimeError:內存訪問超出范圍”。

主要的問題是我從Wasm那里得到的錯誤對我自己解決這個問題根本沒有幫助。 我顯然錯過了一些在幕后真正起作用的主要方面。

如何使用AssemblyScript將TypedArray或ArrayBuffer從JS傳遞給Wasm?

在AssemblyScript中,有許多方法可以從內存中讀取數據。 獲取此數據的最快速最快的方法是在模塊的函數import中使用鏈接函數來返回指向數據本身的指針。

let myData = new Float64Array(100); // have some data in AssemblyScript

// We should specify the location of our linked function
@external("env", "sendFloat64Array")
declare function sendFloat64Array(pointer: usize, length: i32): void;

/**
 * The underlying array buffer has a special property called `data` which
 * points to the start of the memory.
 */
sendFloat64Data(myData.buffer.data, myData.length);

然后在JavaScript中,我們可以使用鏈接函數中的Float64Array構造函數直接返回值。

/**
 * This is the fastest way to receive the data. Add a linked function like this.
 */
imports.env.sendFloat64Array = function sendFloat64Array(pointer, length) {
  var data = new Float64Array(wasmmodule.memory.buffer, pointer, length);
};

但是,有一種更清晰的方法來獲取數據,它涉及從AssemblyScript返回引用,然后使用AssemblyScript加載器。

let myData = new Float64Array(100); // have some data in AssemblyScript

export function getData(): Float64Array {
  return myData;
}

然后在JavaScript中,我們可以使用AssemblyScript提供的ASUtil加載器。

import { instantiateStreaming } from "assemblyscript/lib/loader";

let wasm: ASUtil = await instantiateStreaming(fetch("myAssemblyScriptModule.wasm"), imports);

let dataReference: number = wasm.getData();
let data: Float64Array = wasm.getArray(Float64Array, dataReference);

出於代碼清晰度的原因,我強烈建議使用第二個示例,除非性能絕對至關重要。

祝你的AssemblyScript項目好運!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM