emscripten-core / emscripten

Emscripten: An LLVM-to-WebAssembly Compiler
Other
25.76k stars 3.3k forks source link

WebAssembly feature selection #6361

Closed dschuff closed 5 years ago

dschuff commented 6 years ago

WebAssembly thus far has been in "MVP" state, with all browsers supporting the same set of features. However will soon change, with several features soon to be added including large (shared memory) and small (e.g. nontrapping float-to-int, sign-extension, mutable global).

It turns out that internal feature detection for wasm features is hard [1][2][3][4], and is unlikely to be standardized anytime soon. By "internal" I mean that feature detection can be done from within a wasm module, allowing a single wasm binary to target more than one feature set. So the mechanism we have is to create a small binary that uses a new feature, and test (using the JS API) whether it validates, and we need to have some tooling support to make new features usable.

The question is how. There is a potential combinatorial explosion of possible features that a particular browser version may support, and we don't really want to make users do a separate build for each possible one. It would even be a bit unfortunate if they even had to think individually about each one (will my code benefit from nontrapping float->int? What about sign extension?). For that matter it would probably not be great even if we had some kind of magical automatic support to build a wasm binary with every possible feature combination. But some features definitely are important enough for that (e.g. we have users who don't want to ship without threads).

At the very minimum, we should model the wasm features as cpu features and use the standard compiler flags to enable them (e.g. -mcpu). Upstream clang already does this with the wasm backend (we have subtarget features for SIMD, atomics, NontrappingFPToInt, SignExt, and exception handling, https://github.com/llvm-mirror/llvm/blob/master/lib/Target/WebAssembly/WebAssembly.td#L26) and we can also define named "processors" with any combination of features we want. So we should expose that via emcc as well. To go along with that, we could have some doc akin to caniuse.com but for wasm features, so we'd know which combinations of features actually exist in browsers, and what versions.

In terms of convenience mechanisms to help developers more easily target new features, there are several kinds of possibilities. On one end of the spectrum you might imagine a totally automatic toolchain feature whereby we take a list of all the feature combinations and have the compiler generate a wasm binary for each of them, and package it with JS code and a pile of mini wasm modules that does the feature testing and loads the appropriate wasm module. As an optimization users could choose a subset of the supported flavor combinations. Whether this would even be a win at all would depend on the feature. It's entirely plausible that it would bloat the download more than the savings you'd get from say float2int or signext.

You could also imagine doing this but just for dynamic libraries, and/or you could potentially also allow polyfilling this way for some classes of features (e.g. if you have a lot of nontrapping float->int operations in your IR you could make them all calls to an imported wasm function which is either one instruction or contains an explicit range check). Complexity-wise it would be pretty much equivalent to just building whole modules per-feature-set.

In the end it may end up depending on how important the feature is. The first features to come will most likely be non-trapping float-to-int, and sign-extension, which are small enough that I'm guessing most emscripten users won't benefit enough to make it worthwhile to do something complicated just to get them.

Following that will likely be threads. People care a lot about that, but it seems likely that we'd still want the default to be single-threaded, as it will save some binary size for those who don't want to link libpthread. But it probably makes sense to allow pthread-using builds to work on non-pthread-supporting browsers (which I don't think works today).

In any case, beyond that we should probably have individual tracking issues for those. I guess this issue should just be for general ideas, because we haven't really begun to think concretely about it yet, and now is the time.

stale[bot] commented 5 years ago

This issue has been automatically marked as stale because there has been no activity in the past year. It will be closed automatically if no further activity occurs in the next 7 days. Feel free to re-open at any time if this issue is still relevant.