@ 251021.1 · fetchingraw
current

See rationale for motivating scenarios.

Feature Test

Post-MVP :unicorn:, applications will be able to query which features are supported via has_feature or a similar API :unicorn:. This accounts for the pragmatic reality that features are shipped in different orders at different times by different engines.

What follows is a sketch of what such a feature testing capability could look like.

Since some WebAssembly features add operators and all WebAssembly code in a module is validated ahead-of-time, the usual JavaScript feature detection pattern:

if (foo)
    foo();
else
    alternativeToFoo();

won’t work in WebAssembly (if foo isn’t supported, foo() will fail to validate).

Instead, applications may use one of the following strategies:

  1. Compile several versions of a module, each assuming different feature support and use has_feature tests to determine which version to load.

  2. During the “specific” layer decoding, which will happen in user code in the MVP anyway, use has_feature to determine which features are supported and then translate unsupported feature use into either a polyfill or a trap.

Both of these options could be automatically provided by the toolchain and controlled by compiler flags. Since has_feature is a constant expression, it can be constant-folded by WebAssembly engines.

To illustrate, consider 4 examples:

As a hypothetical (not implemented) example polyfilling the SIMD f64x2 feature, the C++ compiler could provide a new function attribute that indicated that one function was an optimized, but feature-dependent, version of another function (similar to the ifunc attribute, but without the callback):

#include <xmmintrin.h>
void foo(...) {
  __m128 x, y;           // -> f32x4 locals
  ...
  x = _mm_add_ps(x, y);  // -> f32x4.add
  ...
}
void foo_f64x2(...) __attribute__((optimizes("foo","f64x2"))) {
  __m256 x, y;           // -> f64x2 locals
  ...
  x = _m_add_pd(x, y);   // -> f64x2.add
  ...
}
...
foo(...);                 // calls either foo or foo_f64x2

In this example, the toolchain could emit both foo and foo_f64x2 as function definitions in the “specific layer” binary format. The load-time polyfill would then replace foo with foo_f64x2 if (has_feature "f64x2"). Many other strategies are possible to allow finer or coarser granularity substitution. Since this is all in userspace, the strategy can evolve over time.

See also the better feature testing support :unicorn: future feature.