«

《WebAssembly标准入门》读书笔记之JavaScript对象

image.png

—— WebAssembly的到来,使自制虚拟机不再遥远。

[toc]

《WebAssembly标准入门》读书笔记系列


本文是《WebAssembly标准入门》第三章节主要内容,主要介绍JavaScript中WebAssembly相关对象的使用方法。

在浏览器环境中,WebAssembly程序运行在WebAssembly虚拟机之上,页面可以通过一组JavaScript对象进行WebAssembly模块的编译、载入、配置、调用等操作。

WebAssembly对象简介

《WebAssembly标准入门》之快速入门一文中,介绍了WebAssembly中的几个关键概念:模块、内存、表格以及实例。事实上,每个概念在JavaScript中都有对象与之一一对应,分别为:

所有与WebAssembly相关的功能,都属于全局对象WebAssembly。除刚才提到的对象之外,WebAssembly对象中还包含了一些全局方法,如用于执行实例化的WebAssembly.instantiate()

值得注意的是,与很多全局对象(如Date)不同,WebAssembly不是一个构造函数,而是一个命名空间,这与Math对象相似——当我们使用WebAssembly相关功能时,直接调用WebAssembly.XXX(),无须(也不能)使用类似于Date()的构造函数。

本文将具体介绍WebAssembly相关对象时使用的例子,并包含了一些.wasm汇编模块,暂不深入汇编模块的内部,有需要将在后续文章中介绍。

WebAssembly的错误类型

首先介绍下 WebAssembly 相关的错误类型,除了常规的TypeErrorRangeError,与WebAssembly相关的异常还有另外3种,即WebAssembly.CompileErrorWebAssembly.LinkErrorWebAssembly.RuntimeError。这3种异常正好对应WebAssembly程序生命周期的3个阶段,即编译、链接(实例化)和运行。

编译阶段的主要任务是将WebAssembly二进制代码编译为模块(如何转码取决于虚拟机实现)。在此过程中,若WebAssembly二进制代码的合法性无法通过检查,则抛出WebAssembly.CompileError

在链接阶段,将创建实例,并链接导入/导出对象。导致该阶段抛出WebAssembly.LinkError异常的典型情况是导入对象不完整,导入对象中缺失了模块需要导入的函数、内存或表格。另外,在实例初始化时,可能会执行内存/表格的初始化,如使用data段初始化内存:

(data (i32.const 0) "你好,WASM")

以及使用elem段初始化表格:

;;import_table.wat
(module
    (import "js" "table" (table 2 anyfunc))
    (elem (i32.const 0) $func1 $func0) ;;set $func0,$func1 to table
    ...
)

在此过程中,若内存/表格的容量不足以容纳装入的数据/函数引用,也会导致WebAssembly.LinkError

运行时抛出WebAssembly.RuntimeError的情况较多,常见的主要有以下几个。

(1)内存访问越界。试图读写超过内存当前容量的地址空间。 (2)调用函数时,调用方与被调用方签名不匹配。 (3)表格访问越界。试图调用/修改大于等于表格容量的索引处的函数。

在运行时产生的异常中有一种情况需要特别注意:目前JavaScript的Number类型无法无损地表达64位整型数。这意味着虽然WebAssembly支持i64类型的运算,但是与JavaScript对接的导出函数不能使用i64类型作为参数或返回值,一旦在JavaScript中调用参数或返回值类型为i64的WebAssembly函数,将抛出TypeError

下面给出了一些异常的例子。WebAssembly代码如下:

;;exceptions.wat
(module
    (import "js" "mem" (memory 1))
    (import "js" "table" (table 2 anyfunc))
    (elem (i32.const 0) $f0 $f1)
    (type $type_0 (func (result i32)))
    (func $f0 (param i32)(result i32)
        i32.const 13
    )
    (func $f1 (result i32)
        i32.const 65540
        i32.load
    )
    (func (export "call_by_index") (param $index i32)(result i32)
        get_local $index
        call_indirect (type $type_0)
    )
    (func (export "return_i64") (result i64)
        i64.const 0
    )
    (func (export "param_i64") (param i64))
)

JavaScript代码如下:

//exceptions.html
    var table = new WebAssembly.Table({element:'anyfunc', initial:3});
    var memory = new WebAssembly.Memory({initial:1});
    fetchAndInstantiate('exceptions.wasm', {js:{table:table, mem:memory}}).then(
        function(instance) {
            try{
                instance.exports.call_by_index(0)
            }
            catch(err){
                console.log(err);
            }
            try{
                instance.exports.call_by_index(1)
            }
            catch(err){
                console.log(err);
            }
            try{
                instance.exports.call_by_index(2)
            }
            catch(err){
                console.log(err);
            }
            try{
                instance.exports.call_by_index(3)
            }
            catch(err){
                console.log(err);
            }
            try{
                instance.exports.return_i64()
            }
            catch(err){
                console.log(err);
            }
            try{
                instance.exports.param_i64(0)
            }
            catch(err){
                console.log(err);
            }
        }
    );

程序运行后,捕获异常如图所示: ![image.png](http://image.huawei.com/tiny-lts/v1/images/d175226ba05df7ada4dd_628x353.jpg@900-0-90-f.jpg


以下内容涉及很多细节,请重点参考书籍原文:《WebAssembly标准入门》

全局方法

本节将介绍全局对象WebAssembly的全局方法,这些方法主要用于WebAssembly二进制模块的编译及合法性检查。

Promise<WebAssembly.Module>WebAssembly.compile(bufferSource);  
fetch('show_me_the_answer.wasm').then(response =>  
    response.arrayBuffer()
).then(bytes =>
    WebAssembly.compile(bytes)
).then(module =>
    console.log(module.toString()) //"object WebAssembly.Module"
);

WebAssembly.Module 对象

WebAssembly.Instance 对象

WebAssembly.Memory 对象

WebAssembly.Table 对象

分享