(译者注:有些地方真的不知如何翻译,呼唤各路大神的帮助)
关于推动该功能的场景请查看设计理念文档

特性测试

PostMVP版本中, 应用可以通过has_feature或相似的API来查询个特性是否被平台支持。该功能的初衷基于现实情况中,各个特性在不同的引擎里,会在不同的时间以不同的顺序被实现完成。

下面是描述特性测试功能的示例。

由于一些WebAssembly特性增加了操作,而所有的WebAssembly模块的代码都采用事先(ahead-of-time)的验证方式。常见的JavaScript的特性检测是如下模式:

  1. if (foo)
  2. foo();
  3. else
  4. alternativeToFoo();

而在WebAssembly中该代码将无法正常工作(如果 foo 函数不支持,那么foo() 将验证失败)。

在这种情况下,应用可以选择如下的两种策略之一作为替代方法:

  1. 将模块编译成多个不同的版本,对应于多个不同平台所支持的特性,并使用has_feature方法测试决定将要加载的版本。

  2. “特定”层解码阶段, which will happen in user code in the MVP anyway,使用has_feature来决定哪些特性已被支持, 并将不支持的功能映射到polyfill或陷入(trap)方法上实现。

上面两种做法都可使用工具链和编译flag来自动实现,并且has_feature是一个常量表达式,因此它可以被WebAssembly引擎常量合并。

为了说明这个问题,考虑下面四个例子:

  • i32.min_s —— 策略2可以被用来替换 (i32.min_s lhs rhs)到等价的表达式 ,即存储 lhsrhs 到局部变量中,然后使用i32.lt_sselect操作实现相同的功能。
  • 线程 - 如果应用大量地使用#ifdef来进行线程开启/关闭的构建(build),那么策略1是适用的方法。但是,如果应用能够将线程的使用抽象成一些原语,策略2可以用来为正确的原语实现打补丁。
  • mprotect —— 如果引擎 无法使用操作系统提供的signal handling机制来高效实现mprotect,那么mprotect可能永久地变成了一个可选特性。但如果mprotect的使用不是为了保证正确性(而仅仅是为了捕捉bug),即可用nop来替换。相反,为了保证正确性而使用mprotect但存在不依赖mprotect的替代方法,那么mprotect可以依靠应用测试(has_feature "mprotect") 方法来避免调用abort(),用abort()进行替换。has_feature查询操作可以通过现有的__builtin_cpu_supports函数暴露给C++代码。
  • SIMD(单指令多数据流)—— 当SIMD操作有足够优秀的polyfill实现时,例如通过f32x4.mul/add实现f32x4.fma指令, 那么策略2适用(与上面i32.min_s的例子相似)。相反的,当SIMD功能没有足够好的polyfill(例如,f64x2同时引入了操作符类型)时,需要提供替代的算法并在加载时对其进行选择。

下面是一个假定(非真正实现)的对SIMD的f64x2功能进行polyfill的例子,C++编译器可以提供新的功能属性,来标识一个函数是另一个函数的优化,但特性依赖的版本(与 ifunc属性相似,但不具有callback回调):

  1. #include <xmmintrin.h>
  2. void foo(...) {
  3. __m128 x, y; // -> f32x4 locals
  4. ...
  5. x = _mm_add_ps(x, y); // -> f32x4.add
  6. ...
  7. }
  8. void foo_f64x2(...) __attribute__((optimizes("foo","f64x2"))) {
  9. __m256 x, y; // -> f64x2 locals
  10. ...
  11. x = _m_add_pd(x, y); // -> f64x2.add
  12. ...
  13. }
  14. ...
  15. foo(...); // calls either foo or foo_f64x2

在上面的例子中,工具链可以同时在“规范层”的二进制格式中,产生foofoo_f64x2作为函数定义。如果(has_feature "f64x2")测试通过,那么polyfill会在加载时将foo替换成foo_f64x2。许多其他的策略也允许进行细粒度和粗粒度的替换,并由于这些替换都是发生在用户空间,所以策略可以随着时间不断演化。

请在更好的特性测试支持文档中查看进一步的功能。