WebAssembly入門筆記[2]:利用Memory傳遞字節數據
利用靈活的“導入”和“導出”機制,WebAssembly與承載的JavaScript應用之間可以很便利地“互通有無”?!?a href="http://www.rzrgm.cn/artech/p/17982714/hello_wasm_1">與JavaScript的交互》著重演示了如何利用函數的導入和導出實現功能的共享,接下來我們主要關注數據的傳遞或者共享。宗地來說,WebAssembly與宿主程序之間的數據傳遞主要有如下三種手段,本篇文章主要關注Memory。源代碼下載:app3 app4
- Memory:以二進制(字節)的形式傳遞數據;
- Table:傳遞類型化數據(目前只支持函數);
- Global:共享全局變量;
一、導入Memory
顧名思義,一個Memory映射一塊連續的內存,應用以二進制(字節)的形式對它進行讀寫。Memory可以利用導入功能從宿主程序傳遞給WebAssembly,下面的實例演示了這樣的場景:作為宿主的JavaScript應用創建一個Memory對象并寫入相應的內容,然后將其導入到加載的WebAssembly模塊,后者將其中的內容讀出來。
如下所示的代碼片段是承載WebAssembly程序的app.wat文件的內容,我們利用(memory)定義了一個導入的memory,導入路徑為“imports.memory”,后面指定的參數1代表初始大小,單位為Page(64K)。接下來我們定義了四個導出函數,它們會從指定的位置(參數$index表示偏移量)讀取相應長度的字節內容,并將其轉換成對應的類型。具體來說,這四個函數的返回類型分別為i32、i64、f32和f64,也就是WebAssembly支持的四種數據類型。具體的讀取通過執行{i32|i64|f32|f64}.load指令完成,該指令將讀取位置作為唯一參數,所以我們在執行該指令之前需要執行local.get 指令將代表讀取位置的$index參數壓入棧中。
(module
(memory (import "imports" "memory") 1)
(func (export "readAsInt32") (param $index i32) (result i32)
local.get $index
i32.load
)
(func (export "readAsInt64") (param $index i32) (result i64)
local.get $index
i64.load
)
(func (export "readAsSingle") (param $index i32) (result f32)
local.get $index
f32.load
)
(func (export "readAsDouble") (param $index i32) (result f64)
local.get $index
f64.load
)
)有人可能有這樣的疑問,我們在執行load指令的時候為什么沒有指定具體讀取的Memory對象呢?這是因為目前一個WebAssembly模塊只能擁有一個Memory對象,這一限制可能會在后續版本中解除,針對多Memory的提案在兩年前已經提出。
接下來我們依然需要執行“wat2wasm app.wat –o app.wasm”命令對app.wat文件進行編譯,最終生成二進制的模塊文件app.wasm。該文件在index.html頁面的JavaScript腳本中被加載,index.html頁面的內容如下所示。如下面的代碼片段所示,我們調用構造函數WebAssembly.Memory創建了一個Memory對象,并將初始大小設置為1(Page)。我們將這個Memory對象的緩沖區(對應buffer屬性)映射為一個Uint32Array數組。通過設置這個數組的前兩個元素的值(123),我們相應的字節寫入前8個字節。
<html> <head></head> <body> <div id="container"></div> <script> var memory= new WebAssembly.Memory({ initial: 1 }); const array = new Uint32Array(memory.buffer); array[0] = 123; array[1] = 123; WebAssembly .instantiateStreaming(fetch("app.wasm"), {"imports":{"memory":memory}}) .then(results => { var exports = results.instance.exports; document.getElementById("container").innerHTML = `<p>Int32: ${exports.readAsInt32(0)}</p>` + `<p>Int64: ${exports.readAsInt64(0)}</p>` + `<p>Single: ${exports.readAsSingle(0)}</p>` + `<p>Double: ${exports.readAsDouble(0)}</p>` ; }); </script> </body> </html>
我們從WebAssembly模塊實例中導出前面定義的4個函數,并將針對4種不同類型讀取出來的值格式化成HTML呈現出來,下圖所示的就是最終的輸出結果。
二、導出Memory
上面演示了如何將Memory對象從宿主應用中導入到WebAssembly模塊,現在我們反其道而行,將WebAssembly模塊中創建的Memory導出到宿主程序,為此我們將app.wat文件修改為如下的內容。如代碼片段所示,我們利用(memory (export "memory") 1)節點定義了一個初始大小為1Page的Memory,并以名稱“memory”進行導出。隨后定義的導出函數initialize會將作為參數指定的兩個整數寫入前8個字節。針對Memory的寫入通過{i32|i64|f32|f64}.store指令完成,該指令接受兩個參數,第一個代表寫入的位置,第二個代表寫入的值。由于我們具體調用的是i32.store指令,所以在第二次調用的時候指定的寫入位置是4,而不是2。
(module
(memory (export "memory") 1)
(func (export "initialize") (param $first i32) (param $second i32)
i32.const 0
local.get $first
i32.store
i32.const 4
local.get $second
i32.store
)
)在如下所示的index.html中,我們在加載WebAssembly模塊“app.wasm”并得到模塊實例后,調用導出的initialize函數在Memory中寫入兩個整數123。然后我們導出Memory對象,并將它的緩沖區映射為四種類型的數組(Uint32Array、BigUint64Array、Float32Array和Float64Array),并將第一個元素的值讀取出來,這一操作與上面定義針對四個類型定義的讀取函數可謂“異曲同工”。
<html>
<head></head>
<body>
<div id="container"></div>
<script>
WebAssembly
.instantiateStreaming(fetch("app.wasm"))
.then(results => {
var exports = results.instance.exports;
exports.initialize(123,123);
var buffer = exports.memory.buffer;
document.getElementById("container").innerHTML =
`<p>Int32: ${new Uint32Array(buffer)[0]}</p>`+
`<p>Int32: ${new BigUint64Array(buffer)[0]}</p>` +
`<p>Int32: ${new Float32Array(buffer)[0]}</p>`+
`<p>Int32: ${new Float64Array(buffer)[0]}</p>`;
});
</script>
</body>
</html>我們按照相同的方式將讀取出來的四個值轉換成HTML進行輸出,所以我們在瀏覽器上看到相同的結果。
WebAssembly入門筆記[1]:與JavaScript的交互
WebAssembly入門筆記[2]:利用Memory傳遞字節數據
WebAssembly入門筆記[3]:利用Table傳遞引用
WebAssembly入門筆記[4]:利用Global傳遞全局變量
WebAssembly核心編程[1]:wasm模塊實例化的N種方式
WebAssembly核心編程[2]:類型系統
WebAssembly核心編程[3]: Module 與 Instance
WebAssembly核心編程[4]: Memory


利用靈活的“導入”和“導出”機制,WebAssembly與承載的JavaScript應用之間可以很便利地“互通有無”。《與JavaScript的交互》著重演示了如何利用函數的導入和導出實現功能的共享,接下來我們主要關注數據的傳遞或者共享。宗地來說,WebAssembly與宿主程序之間的數據傳遞主要有如下三種手段,本篇文章主要關注Memory。


浙公網安備 33010602011771號