You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on May 29, 2025. It is now read-only.
Lots of issues touch both WebAssembly and general portability. Reference this
issue in the WebAssembly WG issue tracker to create a link to the portability
WG.
A few things based off what we've seen from the wasm WG is that we have three distinct use cases:
wasm that's called as part of JS or calls into it
Pure wasm on the web
wasm run not in a web browser
This and just how the binary is structured leads to some problems. We did talk a lot in this issue about what we can assume with the host environment but we're unsure right now what the best course is. This makes using libstd kind of possible maybe depending on the route taken but we have no satisfactory answer right now.
Portability with wasm is more than just about wasm itself, it also has to do with the executing environment.
The two biggest executing environments are the browser and Node.js, and both environments have completely different APIs and behavior.
And it's not just the APIs either: the way that WebAssembly modules are loaded is different in the browser and Node.js. The way that libraries are created is different. The package managers are different. The tools are different. They really are completely separate in many deep ways.
So we actually have these use cases:
Wasm library/application that wants to use JavaScript APIs that exist in the browser and Node.js.
Wasm library/application that wants to use Node.js APIs.
Wasm library/application that wants to use browser APIs (e.g. DOM).
Wasm library/application that wants to use non-JavaScript APIs (there are already multiple wasm environments which don't include JavaScript at all, e.g. they are built on top of C++, C#, etc.)
Wasm library that wants to be embedded within a larger JavaScript application.
Wasm library that wants to be embedded within a larger Node.js application.
Wasm library that wants to be embedded within a larger browser application.
Wasm library that wants to be embedded within a larger non-JavaScript application (e.g. a wasm plugin embedded within a game engine, similar to what Lua is used for right now).
Essentially, we need to be able to differentiate (at a minimum) between Node.js APIs, browser APIs, general JavaScript APIs, and non-JavaScript APIs.
And the situation is complicated even further because there are things like Electron which allows for an application to use both Node.js and browser APIs at the same time. So it needs to be flexible enough to accommodate things like that.
No WebAssembly only defines the JS and Web APIs as well as the core functionality. A lot of the good stuff that will improve this probably won't be for some time. The standard made it so that we can have a Minimum Viable Product release, but it's pretty spartan in what it is capable of. We might be blocked on this for some time unfortunately.
@mgattozzi Actually I see that page as great news. The layering of the space gives / will give us a nice hierarchy of platforms. Since it looks like no web-assembly APIs are standardized at this moment, we'd probably want something user-definable, like the portability lint working over Cargo features, as a stop gap.
Yeah! I'm more saying it's whatever we define right now and not something defined in the standard, which is fine, but if there is one eventually it'll break possibly the work we've done which isn't as good.
Right now the only standard way to interop with the executing environment is to use wasm import/export, and when doing so you can only import/export these types. In other words:
Global variables of type i32, i64, f32, or f64 (they're actually top-level module-local constants, but the spec calls them globals).
Note: i64 is not supported in JavaScript, and you can only import/export immutable globals (this may change in the future).
Functions with zero or more arguments (each argument can be of type i32, i64, f32, or f64, and you can mix-and-match different types), and it either returns nothing, or it returns a single value (of type i32, i64, f32, or f64).
Note: these are not first-class or higher-order functions, they can only be defined at the top-level of a wasm module.
Memory, which is just a raw vector of bytes. You can get and set i32, i64, f32, or f64 values into various indexes in the memory, and you can mix-and-match different types in the same memory.
Currently there can only be a single Memory per wasm module, which is a quite heavy restriction. But that restriction may be relaxed in the future.
Tables, which is a vector of function pointers (you can mix-and-match different function types in the same table).
Currently there can only be a single Table per wasm module, which is a quite heavy restriction. But that restriction may be relaxed in the future.
Beyond that, nothing else is currently standardized. In other words, no standard APIs, no API conventions, no type conversions, nothing at all.
There is work being done on creating standardized WebAssembly bindings for JavaScript and the browser APIs, but it will be quite some time before it's standardized. And it will be even more time before Node.js APIs are standardized (if they are ever standardized).
So it's up to us (Rust programmers and library authors) to decide on the APIs, and how to squeeze Rust types into the restricted wasm types, etc. There is ongoing work on that, with wasm-bindgen and stdweb, but I think those are outside the scope of the Portability WG.
So something like Cargo features sounds great. That should also handle things like Electron which allow both browser and Node.js APIs (the programmer would just use the Node.js and browser features at the same time).
Alright, standard FFI. Yeah, that should definitely be done with Cargo features. Heck, even post stabilization it's always best to bake fewer things in the compiler.
Activity
mgattozzi commentedon Mar 12, 2018
A few things based off what we've seen from the wasm WG is that we have three distinct use cases:
This and just how the binary is structured leads to some problems. We did talk a lot in this issue about what we can assume with the host environment but we're unsure right now what the best course is. This makes using libstd kind of possible maybe depending on the route taken but we have no satisfactory answer right now.
Pauan commentedon Mar 12, 2018
Portability with wasm is more than just about wasm itself, it also has to do with the executing environment.
The two biggest executing environments are the browser and Node.js, and both environments have completely different APIs and behavior.
And it's not just the APIs either: the way that WebAssembly modules are loaded is different in the browser and Node.js. The way that libraries are created is different. The package managers are different. The tools are different. They really are completely separate in many deep ways.
So we actually have these use cases:
Wasm library/application that wants to use JavaScript APIs that exist in the browser and Node.js.
Wasm library/application that wants to use Node.js APIs.
Wasm library/application that wants to use browser APIs (e.g. DOM).
Wasm library/application that wants to use non-JavaScript APIs (there are already multiple wasm environments which don't include JavaScript at all, e.g. they are built on top of C++, C#, etc.)
Wasm library that wants to be embedded within a larger JavaScript application.
Wasm library that wants to be embedded within a larger Node.js application.
Wasm library that wants to be embedded within a larger browser application.
Wasm library that wants to be embedded within a larger non-JavaScript application (e.g. a wasm plugin embedded within a game engine, similar to what Lua is used for right now).
Essentially, we need to be able to differentiate (at a minimum) between Node.js APIs, browser APIs, general JavaScript APIs, and non-JavaScript APIs.
And the situation is complicated even further because there are things like Electron which allows for an application to use both Node.js and browser APIs at the same time. So it needs to be flexible enough to accommodate things like that.
mgattozzi commentedon Mar 12, 2018
Thanks for the clarification @Pauan!
Ericson2314 commentedon Mar 13, 2018
Yikes. Does the standard just talk about the no-API case?
mgattozzi commentedon Mar 13, 2018
No WebAssembly only defines the JS and Web APIs as well as the core functionality. A lot of the good stuff that will improve this probably won't be for some time. The standard made it so that we can have a Minimum Viable Product release, but it's pretty spartan in what it is capable of. We might be blocked on this for some time unfortunately.
Ericson2314 commentedon Mar 13, 2018
@mgattozzi Actually I see that page as great news. The layering of the space gives / will give us a nice hierarchy of platforms. Since it looks like no web-assembly APIs are standardized at this moment, we'd probably want something user-definable, like the portability lint working over Cargo features, as a stop gap.
mgattozzi commentedon Mar 13, 2018
Yeah! I'm more saying it's whatever we define right now and not something defined in the standard, which is fine, but if there is one eventually it'll break possibly the work we've done which isn't as good.
Ericson2314 commentedon Mar 13, 2018
Agreed, which is why I don't want to define any non-standard cfg tokens in the compiler. By using features, some library takes the fall :D.
Pauan commentedon Mar 14, 2018
Right now the only standard way to interop with the executing environment is to use wasm import/export, and when doing so you can only import/export these types. In other words:
Global variables of type
i32
,i64
,f32
, orf64
(they're actually top-level module-local constants, but the spec calls them globals).Note:
i64
is not supported in JavaScript, and you can only import/export immutable globals (this may change in the future).Functions with zero or more arguments (each argument can be of type
i32
,i64
,f32
, orf64
, and you can mix-and-match different types), and it either returns nothing, or it returns a single value (of typei32
,i64
,f32
, orf64
).Note: these are not first-class or higher-order functions, they can only be defined at the top-level of a wasm module.
Memory, which is just a raw vector of bytes. You can get and set
i32
,i64
,f32
, orf64
values into various indexes in the memory, and you can mix-and-match different types in the same memory.Currently there can only be a single Memory per wasm module, which is a quite heavy restriction. But that restriction may be relaxed in the future.
Tables, which is a vector of function pointers (you can mix-and-match different function types in the same table).
Currently there can only be a single Table per wasm module, which is a quite heavy restriction. But that restriction may be relaxed in the future.
Beyond that, nothing else is currently standardized. In other words, no standard APIs, no API conventions, no type conversions, nothing at all.
There is work being done on creating standardized WebAssembly bindings for JavaScript and the browser APIs, but it will be quite some time before it's standardized. And it will be even more time before Node.js APIs are standardized (if they are ever standardized).
So it's up to us (Rust programmers and library authors) to decide on the APIs, and how to squeeze Rust types into the restricted wasm types, etc. There is ongoing work on that, with wasm-bindgen and stdweb, but I think those are outside the scope of the Portability WG.
So something like Cargo features sounds great. That should also handle things like Electron which allow both browser and Node.js APIs (the programmer would just use the Node.js and browser features at the same time).
jethrogb commentedon Mar 14, 2018
Relevant article https://hacks.mozilla.org/2018/03/making-webassembly-better-for-rust-for-all-languages/
Ericson2314 commentedon Mar 15, 2018
Alright, standard FFI. Yeah, that should definitely be done with Cargo features. Heck, even post stabilization it's always best to bake fewer things in the compiler.